[英]Updating calculated total when a property on the underlying item in a list is changed - wpf
我有一個ViewModel(VM只是簡化示例的背后代碼),其中包含(除其他事項外)一個Pallet
類。 托盤上有很多箱子。 每個盒子里都有幾塊。
我有一個Wpf表單,列出了托盤上的每個盒子以及一個顯示盒子中有多少物品的文本框。 此標簽下面是標簽,顯示托盤上所有物品的總數。
我的問題是,當其中一個文本框發生更改時,如何使標簽更新。 我認為這與屬性更改和集合更改事件有關,但是我似乎無法使其正常工作。
我遇到了似乎可以在集合中添加或刪除項目的答案。 問題是我沒有添加或刪除任何物品。 我只更改集合中某個項目的值。 我知道關於此問題有很多問題,但我一直找不到適合我的問題。
這是一個示例程序:
MainWindow.xaml
<Window>
<StackPanel>
<ItemsControl ItemsSource="{Binding Pallet.BoxesOnPallet}" AlternationCount="100" Tag="{Binding .}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!-- Cast 1 -->
<TextBox Text="{Binding NumberOfPiecesinBox}" Margin="10" Padding="3"></TextBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<TextBlock Text="{Binding Total}" Padding="3"></TextBlock>
</StackPanel>
</Window>
MainWindow.xaml.cs
using System.ComponentModel;
namespace Keops.Mes.Casthouse.Entities.BO
{
public class Box : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Box(int num)
{
NumberOfPiecesinBox = num;
}
public int NumberOfPiecesinBox
{
get { return _numberOfPiecesinBox; }
set
{
_numberOfPiecesinBox = value;
OnPropertyChanged("NumberOfPiecesinBox");
}
}
public int _numberOfPiecesinBox;
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Pallet.cs
using System.Collections.ObjectModel;
using System.Linq;
using Keops.Mes.Casthouse.Entities.BO;
namespace WpfApplication2
{
public class Pallet
{
public Pallet()
{
BoxesOnPallet = new ObservableCollection<Box>
{
new Box(3),
new Box(8),
new Box(5),
new Box(1),
new Box(0)
};
}
public ObservableCollection<Box> BoxesOnPallet { get; set; }
public int ItemTotal
{
get { return BoxesOnPallet.Sum(x => x.NumberOfPiecesinBox); }
set { }
}
}
}
Box.cs
using System.ComponentModel;
namespace Keops.Mes.Casthouse.Entities.BO
{
public class Box : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Box(int num)
{
NumberOfPiecesinBox = num;
}
public int NumberOfPiecesinBox
{
get { return _numberOfPiecesinBox; }
set
{
_numberOfPiecesinBox = value;
OnPropertyChanged("NumberOfPiecesinBox");
}
}
public int _numberOfPiecesinBox;
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
在此示例中,要更新總數,您的Pallet
類將需要通過處理BoxesOnPallet
的CollectionChanged
來“監視”正在添加和從BoxesOnPallet
刪除的項目。 然后,該處理程序應掛鈎/取消掛鈎已添加/已刪除項目的PropertyChanged
事件。 該事件的處理程序可以更新Total
財產Pallet
。 一切都一起工作有點復雜。
public class Pallet : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Pallet()
{
BoxesOnPallet = new ObservableCollection<Box>();
BoxesOnPallet.CollectionChanged += BoxesOnPallet_CollectionChanged;
BoxesOnPallet.Add(new Box(3));
BoxesOnPallet.Add(new Box(8));
BoxesOnPallet.Add(new Box(5));
BoxesOnPallet.Add(new Box(1));
BoxesOnPallet.Add(new Box(0));
}
private void BoxesOnPallet_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (var item in e.NewItems)
{
((Box)item).PropertyChanged += Box_Changed;
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.OldItems)
{
((Box)item).PropertyChanged -= Box_Changed;
}
}
}
void Box_Changed(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Box.NumberOfPiecesinBox))
{
OnPropertyChanged(nameof(BoxesOnPallet));
}
}
public ObservableCollection<Box> BoxesOnPallet { get; set; }
public int ItemTotal
{
get { return BoxesOnPallet.Sum(x => x.NumberOfPiecesinBox); }
set { }
}
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Box : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Box(int num)
{
NumberOfPiecesinBox = num;
}
public int NumberOfPiecesinBox
{
get { return _numberOfPiecesinBox; }
set
{
_numberOfPiecesinBox = value;
OnPropertyChanged(nameof(NumberOfPiecesinBox));
}
}
public int _numberOfPiecesinBox;
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
首先,您需要在Pallet
類中實現INotifyPropertyChanged
,以便創建一種告訴視圖重新讀取正確值的方法。 然后,您需要監視集合中每個項目的PropertyChanged
事件,以便可以在保持受監視項目列表與集合中項目同步的同時,判斷屬性是否已更改。
Pallet.cs
:
public class Pallet : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Pallet()
{
BoxesOnPallet = new ObservableCollection<Box>
{
new Box(3),
new Box(8),
new Box(5),
new Box(1),
new Box(0)
};
}
private ObservableCollection<Box> _boxesOnPallet;
public ObservableCollection<Box> BoxesOnPallet
{
get { return _boxesOnPallet; }
set
{
if (_boxesOnPallet != null)
{
foreach (Box box in _boxesOnPallet)
{
if (box != null)
box.PropertyChanged -= Box_PropertyChanged;
}
_boxesOnPallet.CollectionChanged -= BoxesOnPallet_CollectionChanged;
}
_boxesOnPallet = value;
if (value != null)
{
foreach (Box box in value)
{
if (box != null)
box.PropertyChanged += Box_PropertyChanged;
}
value.CollectionChanged += BoxesOnPallet_CollectionChanged;
}
OnPropertyChanged(nameof(BoxesOnPallet));
}
}
private void BoxesOnPallet_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e?.OldItems != null)
{
foreach (Box box in e.OldItems)
{
if (box != null)
box.PropertyChanged -= Box_PropertyChanged;
}
}
if(e?.NewItems != null)
{
foreach (Box box in e.NewItems)
{
if (box != null)
box.PropertyChanged += Box_PropertyChanged;
}
}
}
private void Box_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals(nameof(Box.NumberOfPiecesinBox)))
OnPropertyChanged(nameof(ItemTotal));
}
public int ItemTotal
{
get { return BoxesOnPallet.Sum(x => x.NumberOfPiecesinBox); }
}
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
同樣,XAML文件中提到的綁定似乎是OneWay
,這意味着將從源到視圖中獲取值,反之亦然; 相反,這應該是TwoWay
綁定。 MainWindow.xaml
:
...
<TextBox Text="{Binding NumberOfPiecesinBox, Mode=TwoWay}" Margin="10" Padding="3"/>
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.