了解将数据从页面传递到用户控件
Posted
技术标签:
【中文标题】了解将数据从页面传递到用户控件【英文标题】:Understanding passing data from a page to a user control 【发布时间】:2020-12-29 07:58:27 【问题描述】:我一直在努力解决如何在页面和 UserControl 之间传递数据,并且可以使用一些说明来说明我可能做错了什么。如果我删除代码的数据部分并仅用 TextBlocks 替换它,我知道 UserControl 正在工作。
我知道 NetWorth 正在显示,但就是不明白为什么没有传递 List<Account>
。我不知道我在这里做错了什么。
PanelNavigation.xaml
<!-- Navigation Section -->
<ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Auto" CanContentScroll="True" Grid.Row="1" Margin="0,0.333,0,0" Grid.ColumnSpan="2">
<UserControls:NavigationPanel DataContext="Binding Accounts"/>
</ScrollViewer>
<!-- Networth Panel -->
<Grid Grid.Row="2" Height="40">
<Border BorderThickness="0,1,0,0" BorderBrush="StaticResource MenuBarBrush" Background="StaticResource BackgroundLightBrush">
<Grid Margin="5,5,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Margin="10,1,10,1" FontSize="16" FontWeight="Normal" Grid.Column="0" Foreground="#FF346C9C" Text="Net Worth" />
<TextBlock FontSize="16" FontWeight="Normal" Grid.Column="1"
HorizontalAlignment="Right" Text="Binding NetWorth, Converter=StaticResource CurrencyConverter"
Foreground="Binding NetWorth, Converter=StaticResource ChangeColor"/>
</Grid>
</Border>
</Grid>
PanelNavigation.xaml.cs
using APTest.ViewModels;
using System.Windows.Controls;
namespace APTest.Views
/// <summary>
/// Interaction logic for PanelNavigation.xaml
/// </summary>
public partial class PanelNavigation : Page
public PanelNavigation()
InitializeComponent();
this.DataContext = new VMNavigationPanel(this);
NavigationPanel.xaml
<UserControl x:Class="APTest.UserControls.NavigationPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:UserControls="clr-namespace:APTest.UserControls"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="400">
<StackPanel>
<StackPanel>
<ItemsControl x:Name="DataTest" ItemsSource ="Binding Accounts">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="Binding TotalBalance" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</StackPanel>
</UserControl>
NavigationPanel.xaml.cs
using System.Windows.Controls;
namespace APTest.UserControls
public partial class NavigationPanel : UserControl
public NavigationPanel()
InitializeComponent();
最后
VMNavigationPanel.cs
using AccountingPlus.ViewModels;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace APTest.ViewModels
class VMNavigationPanel : BaseViewModel
private Page mPage;
private ObservableCollection<Account> accounts;
public ObservableCollection<Account> Accounts
get => accounts;
set
accounts = value;
OnPropertyChanged();
public double NetWorth get; set; = 127492.30;
public VMNavigationPanel(Page page)
mPage = page;
Accounts = new ObservableCollection<Account>();
Account test = new Account();
test.TotalBalance = 100234.23;
Accounts.Add(test);
public class Account
public double TotalBalance get; set;
BaseViewModel.cs
using PropertyChanged;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace APTest
[AddINotifyPropertyChangedInterface]
class BaseViewModel : INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = (Sender, e) => ;
protected void OnPropertyChanged([CallerMemberName] string name = null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
【问题讨论】:
Itemssource 应该绑定 Accounts。 Observablecollection 而不是列表。始终在视图模型上实现 inotifypropertychanged 并在 setter 中引发 propertychanged。不要将页面等 ui 元素传递到视图模型中。 如果您不需要像向导那样向前向后导航,则框架和页面会产生开销。 social.technet.microsoft.com/wiki/contents/articles/… @Andy 你能解释一下将 UI 元素(如页面)传递给 ViewModel 是什么意思吗?我有一个带有 UIControl 的页面,它通过 嵌入到 mainWindow 中,仍在争论这是否是一件好事。至于 INotifyPropertyChanged,我实际上有,但将其删除以进行测试并将其放回去没有任何区别,而 ObservableCollection 没有任何区别。 @AndyAnd 我还在学习,那么你推荐什么而不是框架/页面。举一个我想要达到的目标的例子。想想带有信息和链接列表的侧边导航。然后,这些链接可以将更多内容打开到主要内容部分。我知道我需要在这里使用一个框架,因为我没有看到任何其他方式来更改该主要内容区域,并且该页面必须具有 UserControls。 Vmnavigationpanel 是一个视图模型。它应该完全独立于 ui 工作,并且页面是 ui。我在上面的评论中放了一个链接。这不是随机的。阅读。然后首先谷歌视图模型。取字框。取词页。把它们放在一个盒子里。合上盖子..想想 contentcontrol 和 usercontrol。具有数据类型的数据模板定义了您为视图模型获得的用户界面。 【参考方案1】:首先,您需要模型中的属性来绑定对象。不能绑定字段。
这样您的 Account 类应该是这样的:
public class Account
public double TotalBalance get; set;
还请记住,要在 WPF 中更新 UI,我们需要使用 ObservableCollections。例如,如果您单击一个按钮并将一个项目添加到您的 Accounts 集合中,则该项目将在您的集合中,但在 UI 中,如果您使用 List 集合,您将看不到更新的结果,这就是您需要使用 ObservableCollections 的原因。 https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1?view=netcore-3.1
另一件事是您的绑定拼写错误。在您的 NavigationPanel.xaml 中,它应该是 TotalBalance。
<TextBlock Text="Binding TotalBalnce" />
这是您的视图模型的工作代码:
我还为您实现了 INotifyPropertyChanged 接口,但没有与任何其他属性一起使用。
class VMNavigationPanel : INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged<T>(ref T property, T value, [CallerMemberName] string propertyName = null)
property = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private Page mPage;
public double NetWorth get; set; = 127492.30;
private ObservableCollection<Account> accounts;
public ObservableCollection<Account> Accounts
get => accounts;
set
accounts = value;
public VMNavigationPanel(Page page)
mPage = page;
Accounts = new ObservableCollection<Account>();
Account test = new Account();
test.TotalBalance = 100234.23;
Accounts.Add(test);
public class Account
public double TotalBalance get; set;
【讨论】:
已经进行了这些更改,属性更改位于基类中,我一开始省略了,但没有区别。我已经按照建议反映了帖子的当前更改,并回到了我开始摆弄之前的内容。你没有做任何事情,我不是唯一一个我做了不同的事情并改变了你所拥有的东西,如果它是 null 来创建集合,get 有一个条件。而不是将它放在构造函数中。我移到构造函数没有任何区别。以上是关于了解将数据从页面传递到用户控件的主要内容,如果未能解决你的问题,请参考以下文章
如何将数据从 MainWindow 传递到 MainWindow 内的用户控件?