C# INotifyPropertyChanged未更新WPF UI
我有一个非常简单的WPF表格:C# INotifyPropertyChanged未更新WPF UI,c#,.net,wpf,C#,.net,Wpf,我有一个非常简单的WPF表格: <Window x:Class="WpfApplication1.MainWindow" xmlns:local="clr-namespace:WpfApplication1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xa
<Window x:Class="WpfApplication1.MainWindow"
xmlns:local="clr-namespace:WpfApplication1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="100" Width="100" Name="abcdef">
<Grid>
<ListBox x:Name="listBox1"
ItemsSource="{Binding ElementName=abcdef, Path=Clients}"
DisplayMemberPath="Name" />
</Grid>
</Window>
这是有效的,因为InitializeComponent();是在初始化之后。
但是,如果我将InitializeComponent()放在前面:
InitializeComponent();
Clients=新列表();
添加(新客户端(){ID=1,Name=“element 1”});
Add(newclient(){ID=2,Name=“element 2”});
我希望INotifyPropertyChanged更新我的UI,但事实并非如此
你能告诉我我错过了什么吗
更新:答案是使用datacontext和ObservableCollection而不是List给出的。
然而,datacontext解决方案似乎已经解决了这个问题。那么,我的理解中一定会遗漏一些东西:
public partial class MainWindow : Window
{
public List<Client> Clients { get; set; }
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
Clients = new List<Client>();
Clients.Add(new Client() { ID = 1, Name = "element 1" });
Clients.Add(new Client() { ID = 2, Name = "element 2" });
Clients.Add(new Client() { ID = 3, Name = "element 3" });
Clients.ElementAt(0).Name = "element 1 changed";
Clients.RemoveAt(1);
}
}
公共部分类主窗口:窗口
{
公共列表客户端{get;set;}
公共主窗口()
{
初始化组件();
this.DataContext=this;
Clients=新列表();
添加(新客户端(){ID=1,Name=“element 1”});
Add(newclient(){ID=2,Name=“element 2”});
添加(新客户端(){ID=3,Name=“element 3”});
Clients.ElementAt(0).Name=“element 1已更改”;
客户。移除(1);
}
}
在我的例子中,这段代码更新了控件,我没有使用ObservaleCollection。为什么?
编辑1
阿隆给出了明确的回答:
您需要了解这里有两种不同的变更通知行为。集合更改(例如,添加、删除或重新排序项目)。项目更改(更改元素的名称)。这些由不同的过程处理。INotifyCollectionChanged用于前者,INotifyPropertyChanged用于前者
这是正确的,因为在调试模式下,我们在调用Clients.RemoveAt(1)时不调用FirePropertyChanged
但是,用户界面仍然会随着删除而更新。。。还是不明白;-)
编辑2
现在很清楚了;特别感谢Amnezjak
UI会更新,因为代码在运行时之前使用。如果在单击时添加带有方法Clients.RemoveAt(1)的按钮,则UI不会更新。
现在,如果您将列表替换为ObservableCollection;按钮单击会反映在UI中。
还请注意,您可以删除客户机类中INotifyPropertyChanged的所有实现,因为ObservableCollection会处理这些 问题不在于
INotifyPropertyChanged
,而是因为您的集合不支持更改通知。您需要一个支持更改通知的集合ObservableCollection
通过实现接口来实现这一点
使用observedcollection
而不是应该有效的List
。尝试使用而不是普通List。集合需要实现INotifyPropertyChanged,而不是模型类。ObservableCollection实现INotifyPropertyChanged
public class ObservableCollection<T> : Collection<T>,
INotifyCollectionChanged, INotifyPropertyChanged
公共类ObservableCollection:Collection,
INotifyCollectionChanged,INotifyPropertyChanged
编辑(问题更改后)
observateCollection
如果您想在应用程序运行期间(例如,单击按钮)修改收集,则具有优势。在这种情况下,列表
将不起作用
这里所有的误解都是Bidding toDataContext
和窗口上的另一个元素(控件)之间的区别。第一个问题被解决了好几次,同样是在显示窗口时(然后您的集合按您希望的方式填充)。我认为后者只有在初始化组件时才能解决。在这种情况下,当您在InitializeComponent
之后创建集合(无论这是ObservableCollection
还是List
)时,绑定将获得空值,并且以后不会要求它
上一部分
它不起作用,因为您正在使用ElementName
进行绑定,这在组件初始化期间确实得到了解决,并且不会延迟。要使它起作用,您必须:
DataContext
设置为this
,然后删除
ElementName
从您的绑定中删除。这样,它无论在什么情况下都能正常工作
无论您将其放在初始化组件之前还是之后
<ListBox x:Name="listBox1"
ItemsSource="{Binding Path=Clients}"
DisplayMemberPath="Name" />
public MainWindow()
{
Clients = new List<Client>();
Clients.Add(new Client() { ID = 1, Name = "element 1" });
Clients.Add(new Client() { ID = 2, Name = "element 2" });
InitializeComponent();
this.DataContext = this;
}
谢谢你的回答 阿姆内兹贾克, 一旦我将datacontext设置为此,即使使用List而不是ObservableCollection,我也不再有任何问题:
InitializeComponent();
Clients = new List<Client>();
Clients.Add(new Client() { ID = 1, Name = "element 1" });
Clients.Add(new Client() { ID = 2, Name = "element 2" });
this.DataContext = this;
Clients.Add(new Client() { ID = 3, Name = "element 3" });
InitializeComponent();
Clients=新列表();
添加(新客户端(){ID=1,Name=“element 1”});
Add(newclient(){ID=2,Name=“element 2”});
this.DataContext=this;
添加(新客户端(){ID=3,Name=“element 3”});
UI从模型中不断更新
因此,你能解释一下在这种情况下切换到ObservableCollection有什么好处吗?你所做的只是强制重新绑定。事实上,你不应该用这个代码看到元素3。说真的……相信另一个SOer,使用
ObservableCollection
,它支持更改通知。但是我看到元素3,你甚至可以添加客户端。ElementAt(0).Name=“元素1已更改”;更改将反映在UI中。请确保我信任回答我问题的人,因为他们更有经验。我的目的是清楚地理解概念。这是完全错误的。但我将描述正在发生的事情。实际上,您在这里看到的是This.DataContext=This.DataContext
。这显然没有任何作用us.is所做的是在DataContext
上引发PropertyChanged
事件,这会导致依赖于DataContext
的任何内容重新绑定。因为DataContext
是默认上下文(出于明显的原因)对于每个控件,这将导致WPF控件上的所有内容重新绑定。但是,如果在稍后阶段向客户端添加更多项,则
public class ObservableCollection<T> : Collection<T>,
INotifyCollectionChanged, INotifyPropertyChanged
<ListBox x:Name="listBox1"
ItemsSource="{Binding Path=Clients}"
DisplayMemberPath="Name" />
public MainWindow()
{
Clients = new List<Client>();
Clients.Add(new Client() { ID = 1, Name = "element 1" });
Clients.Add(new Client() { ID = 2, Name = "element 2" });
InitializeComponent();
this.DataContext = this;
}
public ObservableCollection<Client> Clients
{
get { return (ObservableCollection<Client>)GetValue(ClientsProperty); }
set { SetValue(ClientsProperty, value); }
}
public static readonly DependencyProperty ClientsProperty =
DependencyProperty.Register("Clients", typeof(ObservableCollection<Client>), typeof(MainWindow));
InitializeComponent();
Clients = new List<Client>();
Clients.Add(new Client() { ID = 1, Name = "element 1" });
Clients.Add(new Client() { ID = 2, Name = "element 2" });
this.DataContext = this;
Clients.Add(new Client() { ID = 3, Name = "element 3" });