Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.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# INotifyPropertyChanged未更新WPF UI_C#_.net_Wpf - Fatal编程技术网

C# INotifyPropertyChanged未更新WPF UI

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

我有一个非常简单的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/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 to
DataContext
和窗口上的另一个元素(控件)之间的区别。第一个问题被解决了好几次,同样是在显示窗口时(然后您的集合按您希望的方式填充)。我认为后者只有在初始化组件时才能解决。在这种情况下,当您在
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" });