我有一个列表对象,它在模型类中定期更新。我想使用计算属性将这些更改从我的模型传播到我的视图。
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经常更新,但列表对象本身永远不会被重新分配。
为什么会这样?有没有办法在不重建列表的情况下触发更新?
如果使用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
问题是可以认识到,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
维护/同步它。