C# 在WPF的默认构造函数中设置DataContext的顺序
我尝试在WPF的默认构造函数中设置DataContext属性的顺序C# 在WPF的默认构造函数中设置DataContext的顺序,c#,wpf,user-interface,data-binding,datacontext,C#,Wpf,User Interface,Data Binding,Datacontext,我尝试在WPF的默认构造函数中设置DataContext属性的顺序 <StackPanel> <ListBox ItemsSource="{Binding MyItems, PresentationTraceSources.TraceLevel=High}"></ListBox> <TextBlock Text="{Binding SomeText}"></TextBlock> <T
<StackPanel>
<ListBox ItemsSource="{Binding MyItems, PresentationTraceSources.TraceLevel=High}"></ListBox>
<TextBlock Text="{Binding SomeText}"></TextBlock>
<TextBlock Text="{Binding SomeNum}"></TextBlock>
<TextBlock Text="{Binding Path=Person.Name}"></TextBlock>
<ListBox ItemsSource="{Binding Path=PersonList}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
调用InitializeComponent
方法后,对属性值的更改不会反映在UI中,但使用INotifyPropertyChanged
的属性除外。到目前为止一切都很清楚
但是,我注意到列表项的更改也反映在UI中。为什么
我一直认为,为了反映从集合中添加/删除,我需要ObservableCollection,并在list对象上实现INotifyPropertyChanged
,以检测这些对象的修改。这是什么意思
2)在初始化组件
方法
public partial class MainWindow : Window, INotifyPropertyChanged
{
private string someText = "Default text";
public List<string> MyItems { get; set; }
public List<Person> PersonList { get; set; }
public Person Person { get; set; }
public int SomeNum { get; set; }
public string SomeText
{
get
{
return someText;
}
set
{
someText = value;
OnPropertyChanged("SomeText");
}
}
public MainWindow()
{
this.DataContext = this;
MyItems = new List<string>();
PersonList = new List<Person>();
Person = new Person();
InitializeComponent();
/*These changes are not reflected in the UI*/
SomeNum = 7;
Person.Name = "Andy";
/*Changes reflected with a help of INotifyPropertyChanged*/
SomeText = "Modified Text";
/* Changes to the Lists are reflected in the UI */
MyItems.Add("Red");
MyItems.Add("Blue");
MyItems.Add("Green");
MyItems[0] = "Golden";
PersonList.Add(new Person() { Name = "Xavier" });
PersonList.Add(new Person() { Name = "Scott" });
PersonList[0].Name = "Jean";
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
public class Person
{
public string Name { get; set; } = "Default Name";
}
为什么在MVVM的
InitializeComponent
之后设置DataContext属性是一种不好的做法?您能更详细地描述它吗?或者给出一个简单的代码示例吗?当视图模型属性没有触发PropertyChanged事件时,当然必须在将视图模型实例分配给视图的DataContext之前设置其值
但是,在调用InitializeComponent之前或之后分配DataContext并不重要:
给定一个类似于
<TextBlock Text="{Binding SomeText}"/>
及
我一直认为,为了反映从集合中添加/删除的情况,我需要ObservableCollection
,并在list对象上实现INotifyPropertyChanged
,以检测这些对象的修改
如果希望在视图模型更改期间可靠地更新UI,可以这样做
这是什么意思
“意思”是,在您的特定场景中,您所做的假设是无效的。WPF组件经历了各种初始化步骤,其中只有一些作为InitializeComponent()
方法的一部分出现
例如,如果要将值更新的代码移动到Loaded
事件的处理程序中,您会发现一些更新反映在UI中,但不是全部
如果使用优先级为DispatcherPriority.SystemIdle
的Dispatcher.InvokeAsync()
将相同的代码移动到通过调用的方法中,您会发现除了由INotifyPropertyChanged
支持的更新之外,不会观察到任何更新。在这种情况下,您将显式地等待初始化的每个方面都完成,并且初始化代码不再有机会观察更新的值
这都是时间问题。在用户界面观察到某个值之前设置该值的任何代码都可以成功地执行此操作,而无需INotifyPropertyChanged
或等效工具。但在这种情况下,您完全受当前框架实现的支配。初始化的不同部分发生在不同的时间,并且这些都没有记录,所以您依赖于未记录的行为。它可能不会改变,但你无法确定
为什么在MVVM的
InitializeComponent
之后设置DataContext属性是一种不好的做法
不是。不要相信你所读到的一切,甚至(尤其是!)在互联网上
如果要放弃执行INotifyPropertyChanged,则在分配数据上下文
之前初始化所有视图模型数据将非常重要。但是,即使在调用InitializeComponent
后分配DataContext
,也会观察到该分配(因为DataContext
是一个依赖属性,因此会向框架提供属性更改通知),UI会从视图模型数据中检索所有绑定数据
重要的是在分配
DataContext
之前初始化视图模型数据。相对于InitializeComponent()
发生这种情况的位置并不重要。为什么在InitializeComponent之后设置DataContext属性是MVVM的错误做法?事实并非如此。谁说的?只需确保您的所有属性在下面的注释中触发PropertyChanged事件“如果使用MVVM,请务必注意,在调用InitializeComponent()之前应设置DataContext,否则您的ViewModel绑定将无法正确设置。InitializeComponent()调用所有属性绑定获取程序,因此如果先调用它,则在对每个属性再次调用NotifyPropertyChanged之前,绑定将无法获取正确的值。”
DataContext = new { SomeText = "Hello, World." };
InitializeComponent();
InitializeComponent();
DataContext = new { SomeText = "Hello, World." };