Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在WPF的默认构造函数中设置DataContext的顺序_C#_Wpf_User Interface_Data Binding_Datacontext - Fatal编程技术网

C# 在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

我尝试在WPF的默认构造函数中设置DataContext属性的顺序

<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." };