我已经尝试过关于此问题的其他主题,但我没有找到一个有效的实现问题。基本上,我有一个名为“FruitBasket”的ObservableCollection,它包含不同种类的水果。 FruitBasket本身包含 ObservableCollections ,用于通过的每种相应类型的水果,以便它们可以用作 ListViews 的 ItemSources (由其名称表示) AppleContainer“和”OrangeContainer“),每个都展示一种水果。因为水果类本身实现了INotifyPropertyChanged,修改它们的值会触发对ListView控件的更新,但是,FruitBasket具有从集合中所有其他水果的权重派生的“TotalWeight”属性。我希望“TotalWeight”更新UI中的 Label 控件,而无需刷新UI。触发关于实际 ObservableCollection 本身的属性更改的通知,而不仅仅是其组成成员更加困难,而且我还没有找到任何可行的解决方案(或者我已经正确实现)
public class FruitBasket : ObservableCollection<IFruit>
{
private decimal _totalWeight;
public FruitBasket()
{
this.Add(new OrangeContainer(this));
this.Add(new AppleContainer(this));
}
public OrangeContainer Oranges
{
get { return (OrangeContainer)this.Items[0]; }
}
public AppleContainer Apples
{
get { return (AppleContainer)this.Items[1]; }
}
public decimal TotalWeight
{
get { return _totalWeight; }
set { _totalWeight = value; }
}
internal void UpdateWeight(IFruit caller)
{
_totalWeight = 0;
foreach (Orange orng in (OrangeContainer)this.Items[0])
{
_totalWeight += orng.Weight;
}
foreach (Apple appl in (AppleContainer)this.Items[1])
{
_totalWeight += appl.Weight;
}
}
答案 0 :(得分:2)
每当添加,删除项目或任何项目的权重属性发生变化时,您都需要调用FruitBasket的INotifyPropertyChanged.PropertyChanged事件。
让我们把它分成两个任务:
我已将这两项任务分成两类,以遵循单一责任原则:
1) - 这会处理项目的PropertyChanged事件:
public abstract class ExtendedObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
protected override void ClearItems()
{
foreach (var item in Items) item.PropertyChanged -= ItemPropertyChanged;
base.ClearItems();
}
protected override void InsertItem(int index, T item)
{
item.PropertyChanged += ItemPropertyChanged;
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
this[index].PropertyChanged -= ItemPropertyChanged;
base.RemoveItem(index);
}
protected override void SetItem(int index, T item)
{
this[index].PropertyChanged -= ItemPropertyChanged;
item.PropertyChanged += ItemPropertyChanged;
base.SetItem(index, item);
}
abstract void ItemPropertyChanged(object sender, PropertyChangedEventArgs e);
}
2) - 必要时重新计算TotalWeight
public class FruitBasket : ExtendedObservableCollection<IFruit>
{
protected override void ItemPropertyChanged(object sender, PropertyChangedEventArgs e){
UpdateWeight();
OnPropertyChanged("TotalWeight")
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
UpdateWeight();
OnPropertyChanged("TotalWeight")
base.OnCollectionChanged(e);
}
}
当然你的Fruit应该实现INotifyPropertyChanged接口。你会发现很多例子如何做到这一点。这很简单。
答案 1 :(得分:0)
我找到了问题的根源。我将从最明显的开始:
我并不擅长在UI中为水果篮可观察集合对象本身分配datacontext,因为我是其集合成员(OrangeContainer和AppleContainer)。在UI窗口的初始化中,将datacontext分配给ListView对象是第二天性。我没有将XAML中正确节点的datacontext与后面代码中的初始化方法中的Fruit Basket对象完全匹配(我之前应该检查过)。
由于在XAML和初始化方法之间未对齐datacontext / binding的赋值,因此我的水果篮可观察集合中的propertychanged事件从未触发,就像OrangeContainer和AppleContainer集合中的Apple和Orange对象一样。 FruitBasket。所以,在Orange类宣言中我们有这个:
public class Orange : INotifyPropertyChanged, IFruit
这样的实现
public event PropertyChangedEventHandler PropertyChanged;
public void PropChange(string prop)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
当在 Weight 属性设置器中调用 PropChange 方法时, this.PropertyChanged 不会为null,一切都会正常工作
FruitBasket课程有点棘手。由于UI代码中存在不正确匹配的问题,每当我尝试通知属性更改时, this.PropertyChanged 都会返回 null 。但是,它有点混乱,因为与 Orange 或 Apple 类不同,它继承了ObservableCollection(如果我们想要特定的话,声明中的ObservableCollection)。我知道 ObservableCollection 实际上只是一个实现INotifyPropertyChanged和INotifyCollectionChanged接口的 Collection 类。现在看.NET管道开源(赞美主)
真的很高兴无论如何,实现这一点变得更加混乱,因为我一直看到这个:
警告1&#39; TestingObsColNotify.FruitBasket.PropertyChanged&#39;隐藏继承成员&#39; System.Collections.ObjectModel.ObservableCollection.PropertyChanged&#39;。要使当前成员覆盖该实现,请添加override关键字。否则添加新关键字。 C:\ Testing VS Project \ TestingObsColNotify \ TestingObsColNotify \ FruitBasket.cs 60 50 TestingObsColNotify
我仍然看到这一点,但我的实现工作正常,因为它是INotifyProperty的继承通过ObservableCollection更改的结果,如我原来的类声明中所见
public class FruitBasket : ObservableCollection<IFruit>
这只是为了让所有东西都能正常工作的最后一个元素,这就是将INotifyPropertyChanged添加到类本身,如下所示:
public class FruitBasket : ObservableCollection<IFruit>, INotifyPropertyChanged
它看起来有点冗余和不优雅,但我没有尝试覆盖和冥想来自ObservableCollection的INotifyPropertyChanged的继承(或者我能理解的最好)。
所以我们拥有它,现在一切正常,没有MVVM。我以后肯定会继续使用该模式,但很高兴解决这个问题,而不是懒得只是在UI方面重新分配代码隐藏方法中的控件内容。
感谢那些来到这里并做出贡献的人,感谢您抽出宝贵时间作出回应。
答案 2 :(得分:-1)
如果使用绑定,请将接口INotifyPropertyChanged
添加到您的班级。如果安装了ReSharper,请接受建议以实现该接口。然后,每当您想要更新任何文本框时,请使用属性PropertyChanged
的名称拨打TotalWeight
,请参阅https://softwareengineering.stackexchange.com/questions/228067/where-do-put-inotifypropertychanged-interface-in-model-or-viewmodel。每当您更新任何ObservableCollections
时,请手动更新TotalWeight
,然后调用前面提到的PropertyChanged
以告知用户界面更新自己。我已经使用这种技术将更新从ViewModel推送到View(即从类到XAML),对于一些相当复杂的场景,它运行得非常好。
我还建议遵循MVVM的学习曲线,以这种方式编写的项目往往更具可扩展性,更易于维护,更易于使用。