【问题标题】:INotifyPropertyChanged is not working MVVMINotifyPropertyChanged 不工作 MVVM
【发布时间】:2016-12-19 04:47:50
【问题描述】:

我有一个 Observable 集合,但是在更新集合之后,即使在引发 Property Changed 事件后,我的 Listview 也没有更新,请参见下面的代码:-

看下面的 XAML:-

 <ListView  Grid.Row="1" Grid.Column="0" Name="lvGroups" Margin="0,34,0,0" 
Grid.RowSpan="2" ItemsSource="{Binding Path=*VideoGroupList*,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<GridView>
<GridViewColumn Width="150" DisplayMemberBinding="{Binding *Name*}" />
</GridView>

看下面的类

 public class VideoGroupViewModel : ObservableEnitiy
 {
   public ObservableCollection<Group> VideoGroupList { get; set; }
 }

  public abstract class ObservableEnitiy : INotifyPropertyChanged
 {
   public event PropertyChangedEventHandler PropertyChanged;
   protected virtual void OnPropertyChanged(string propertyName)
   {
     this.VerifyPropertyName(propertyName);
      if (this.PropertyChanged != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            this.PropertyChanged(this, e);
        }
   }
 }

[Serializable]
public class Group : PropertyChangedNotification
{
    public int ID { get; set; }
    [Required(ErrorMessage = "Group name is required.")]
    public string *Name*
    {
        get { return GetValue(() => Name); ; }
        set
        {
            SetValue(() => Name, value);
        }
    }
    [XmlIgnore]
    public bool IsSelected { get; set; }
}  


     protected T GetValue<T>(Expression<Func<T>> propertySelector)
    {
        string propertyName = GetPropertyName(propertySelector);

        return GetValue<T>(propertyName);
    }

我这样叫

 VideoGroupList = new ObservableCollection<Group>(videoGroupManager.GetVideoGroups());
 OnPropertyChanged("VideoGroupList");

【问题讨论】:

  • 这个问题通常是由于控件刷新事件没有识别出控件已经改变引起的。通常有效的技巧是在更新列表之前添加 VideoGroupList = null。
  • 请注意,在 ItemsSource Binding 上设置 Mode=TwoWayUpdateSourceTrigger=PropertyChanged 是多余的。它没有任何效果,因为没有从绑定的目标到源属性的数据流。
  • @jdweng 我在更新列表之前尝试了 VideoGroupList = null 但不起作用。 :(
  • 您确定您正在获取代码吗?在代码上设置断点。
  • @jdweng 是的,我尝试过,但没有运气

标签: c# wpf mvvm


【解决方案1】:

添加以下 using 语句:

using System.Collections.Generic;
using System.Linq;

将您的 VideoGroupList 行更改为:

    VideoGroupList.Clear();
    videoGroupManager.GetViewGroups().ToList().ForEach(x => VideoGroupList.Add(x));

这更好地利用了 ObservableCollection 中内置的更改通知

【讨论】:

    【解决方案2】:

    根据 MSDN 文档,CollectionChanged 将在添加、删除和更改 ObservableCollection 中的元素时引发。然而,我发现情况并非如此。 ObservableCollection.CollectionChanged 只会在添加/删除时抛出。 我改用this FullyObservableCollection here,修改后让 T 成为我的 ViewModelBase 类,而不是直接使用 INotifyPropertyChanged。

    当我声明我的属性时,我使用带有以下输出的 sn-p: private FullyObservableCollection<Group> _videoGroupList; public FullyObservableCollection<Group> VideoGroupList { get { return _videoGroupList; } set { if(_videoGroupList == value) return; var nil = _videoGroupList == null; _videoGroupList = value; // If null before and not after (declaring it after being null), // call OnPropertyChanged on Change of Collection. if(nil && _videoGroupList != null) _videoGroupList.CollectionChanged += (s,e) => OnPropertyChanged(nameof(VideoGroupList)); OnPropertyChanged(); } } 这样,您将始终对集合及其每个成员的添加、删除、替换和更改操作有 INotifyPropertyChanged 通知。这将为您节省很多麻烦,因为如果其中数十万个属性之一发生更改,您无需重新实例化整个集合。 不过请记住在构造函数中对其进行初始化。 :)

    【讨论】:

    • 这似乎会引发很多可能不必要的属性更改事件,你的最后一行,OnPropertyChanged();将导致当前数据上下文重新评估其所有绑定,这对于深度或大型对象图来说可能是一项非常昂贵的操作。最好使用实现自己的属性通知的 ViewModel 的 ObservableCollection,以便仅在需要时隔离属性更改,例如 stackoverflow.com/a/4040810/4490
    • @benPearce 我注意到最后一个OnPropertyChanged(); 仅在集合完全设置时才被调用,而不是在成员更改时调用。 CollectionChanged() =&gt; OnPropertyChanged(nameof(MyCollection)); 将导致在每次更改集合时都刷新所有内容。但是,如果您的 ListBoxListView 使用 VirtualizingStackPanel 或类似名称,不幸的是,在大多数情况下,必须在 DataTriggers 等上进行可视化更改。但是,在 ~20k 元素上总共有 ~200k 绑定的较小列表仍然可以。不过不能说更多。
    猜你喜欢
    • 2018-03-19
    • 1970-01-01
    • 2011-06-25
    • 2013-04-01
    • 2011-06-03
    • 1970-01-01
    • 2011-10-10
    • 2018-06-19
    • 1970-01-01
    相关资源
    最近更新 更多