在NotifyPropertyChanged WPF之后,计算列表不会更新

问题描述 投票:0回答:2

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

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事件之前输入断点时,我发现我的集合确实更新了我在模型和ViewModel中的所需方式。

如果我更改此行:

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

至:

public IList<Stripe> StripeCollection => new List<Stripe>(MyZebra.GetStripes);

绑定确实更新。但是,每次条纹更改时,我都不想复制列表。 (显然Zebras经常更换条纹)。

MyZebras中的List经常更新,但列表对象本身永远不会被重新分配。

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

c# wpf
2个回答
0
投票

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

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

这样,您可以通知视图该属性已更改。如果你想从另一点做到这一点,你需要打电话给OnPropertyChanged(nameof(StripeCollection))

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


0
投票

问题是可以认识到,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控件将被刷新(整个列表)。

更好的解决方案是使用ObservableCollection,正如Jordy van Eijk所建议的那样。

更新:

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();};

另一个解决方案是对StripeCollection使用ObservableCollection并在处理程序中使用MyZebra.Stripes维护/同步它。

© www.soinside.com 2019 - 2024. All rights reserved.