【问题标题】:Calculated List does not update after NotifyPropertyChanged WPFNotifyPropertyChanged WPF 后计算列表不更新
【发布时间】:2018-02-27 00:06:38
【问题描述】:

我有一个在模型类中定期更新的列表对象。我想使用计算属性将这些更改从我的模型传播到我的视图。

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private Zebra MyZebra { get; } = new Zebra();

    public IList<Stripe> StripeCollection => MyZebra.Stripes;

    public ViewModel()
    {
        MyZebra.StripesChanged += (sender, args) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("StripeCollection"));
    }
}

我像这样绑定到 WPF 对象的 ItemsSource:

ItemsSource="{Binding StripeCollection}"

当事件触发时,它不会更新我的绑定。当我在触发 PropertyChanged 事件之前输入断点时,我看到我的集合确实更新了我希望它在模型和视图模型中的方式。

如果我改变这一行:

public IList&lt;Stripe&gt; StripeCollection =&gt; MyZebra.GetStripes;

到:

public IList&lt;Stripe&gt; StripeCollection =&gt; new List&lt;Stripe&gt;(MyZebra.GetStripes);

绑定确实更新了。但是,我对每次条纹更改时都复制列表不感兴趣。 (显然斑马经常更换条纹)。

MyZebras 内部的 List 会经常更新,但 list 对象本身永远不会重新分配。

为什么会这样?有没有办法在不重建列表的情况下触发更新?

【问题讨论】:

  • MyZebra.StripesChanged 的​​实际类型是什么?
  • public event EventHandler StripesChanged;
  • 我复制粘贴错位了,想问一下集合的实际类型是什么MyZebra.Stripes
  • 另一种方法是查看ObservableCollection 而不是IList
  • @JordyvanEijk 很遗憾,我无法更改 Zebra 的实现。

标签: c# wpf


【解决方案1】:

问题在于,StripeCollection(对 MyZebra.Stripes 的引用)的值没有改变,因此尽管有 PropertyChanged 通知,但您看不到任何变化。
您已经找到了一种可能的解决方案。

另一个避免生成新对象的方法是将StripeCollection 中的StripesChanged 处理程序临时设置为null。为了你能做到,你必须重写StripeCollection

public IList<Stripe> StripeCollection {
  get { return _stripeCollection; }
  set {
    _stripeCollection = value;
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StripeCollection)));
  }
} 
private IList<Stripe> _stripeCollection=MyZebra.Stripes;

MyZebra.StripesChanged += (sender, args) => {var tmpCol=StripeCollection; StripeCollection=null; StripeCollection=tmpCol;};

结果是您的 UI-Control 将被刷新(整个列表)。

更好的解决方案是按照 Jordy van Eijk 的建议使用 ObservableCollection。

更新

CollectionView 还有一种解决方案:

public ICollectionView StripeCollection
{
    get { return _stripeCollection; }
    set
    {
        _stripeCollection = value;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StripeCollection)));
    }
}
private ICollectionView _stripeCollection =new CollectionView(MyZebra.Stripes);
MyZebra.StripesChanged += (sender, args) => {StripeCollection.Refresh();};

另一种解决方案是使用 ObservableCollection 处理 StripeCollection 并在处理程序中将其与 MyZebra.Stripes 保持/同步。

【讨论】:

  • 这个解决方案最终会降低我目前的性能。瓶颈是 WPF 在重新分配列表时完全刷新列表(我目前是如何做的)。此解决方案使 UI 刷新列表两次。首先是null,然后是更新后的next。
【解决方案2】:

如果您使用 StripeCollection 的设置器,您需要通过触发设置属性后更改的属性来通知视图。

private IList<Stripe> _stripeCollection;
public IList<Stripe> StripeCollection {
  get { return _stripeCollection; }
  set {
    _stripeCollection = value;
    OnPropertyChanged();
  }
} //=> MyZebra.Stripes

这样您可以通知视图属性已更改。如果您想从另一个角度执行此操作,您需要致电OnPropertyChanged(nameof(StripeCollection))

如果您想通知视图 StripeCollection 已从 Zebra 对象内部设置。 You can use EventAggregation / Publish and Subscribe

【讨论】:

    猜你喜欢
    • 2023-01-15
    • 2023-03-14
    • 1970-01-01
    • 2012-11-24
    • 1970-01-01
    • 2013-11-12
    • 1970-01-01
    • 2019-05-12
    • 1970-01-01
    相关资源
    最近更新 更多