gpt4 book ai didi

c# - 通知/绑定(bind)父属性以计算子属性的总和

转载 作者:太空狗 更新时间:2023-10-29 22:23:27 25 4
gpt4 key购买 nike

我有两个类,一个用于ViewModel,一个用于Product。Product 类有一个名为Line Total 的属性,ViewModel 类有一个名为Total Amount 的属性。 Product 类绑定(bind)到 DataGrid 和用户插入随后自动更新行总计的数量。

这是 ViewModel 类:

public class ViewModel : INotifyPropertyChanged
{

public ObservableCollection<Product> products { get; set; }// the children

private decimal _TotalAmount;
public decimal TotalAmount // <=== has to hold sum of [products.LineTotal]
{
get
{
return totalAmount;
}
set
{
if (value != _TotalAmount)
{
_TotalAmount = value;
onPropertyChanged(this, "TotalAmount");
}
}
}

这是 Product 类的子类:

public class Product : INotifyPropertyChanged
{
private decimal _LineTotal;
public decimal LineTotal
{
get
{
return _LineTotal;
}
set
{
if (value != _LineTotal)
{
_LineTotal = value;
onPropertyChanged(this, "LineTotal");
}

}

}
}

我的问题是:TotalAmount 如何计算所有 Products [Line Total] 的总和?子 Products 如何通知父 ViewModel 更新 TotalAmount

类似于:

foreach(var product in Products)
{
TotalAmount += product.LineTotal;
}

最佳答案

实现此目的的一种方法是,每次用户编辑总计行以及每次向 ObservableCollection 添加或删除产品时重新计算总金额。

由于 Product 实现了 INotifyPropertyChanged 并在设置新行总数时引发 PropertyChanged 事件,ViewModel可以处理该事件并重新计算总金额。

ObservableCollection 有一个 CollectionChanged 事件,当一个项目被添加到其中或从中删除时会引发该事件,因此 ViewModel 也可以处理该事件并重新计算。 (如果产品只能更改而不能由用户添加/删除等,则这部分并不是真正必要的)。

您可以试试这个小程序,看看它是如何完成的:

代码隐藏

public partial class MainWindow : Window
{
ViewModel vm = new ViewModel();

public MainWindow()
{
InitializeComponent();

vm.Products = new ObservableCollection<Product>
{
new Product { Name = "Product1", LineTotal = 10 },
new Product { Name = "Product2", LineTotal = 20 },
new Product { Name = "Product3", LineTotal = 15 }
};

this.DataContext = vm;
}

private void AddItem(object sender, RoutedEventArgs e)
{
vm.Products.Add(new Product { Name = "Added product", LineTotal = 50 });
}

private void RemoveItem(object sender, RoutedEventArgs e)
{
vm.Products.RemoveAt(0);
}
}

public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<Product> _products;
public ObservableCollection<Product> Products
{
get { return _products; }
set
{
_products = value;

// We need to know when the ObservableCollection has changed.
// On added products: hook up eventhandlers to their PropertyChanged events.
// On removed products: recalculate the total.
_products.CollectionChanged += (sender, e) =>
{
if (e.NewItems != null)
AttachProductChangedEventHandler(e.NewItems.Cast<Product>());
else if (e.OldItems != null)
CalculateTotalAmount();
};

AttachProductChangedEventHandler(_products);
}
}

private void AttachProductChangedEventHandler(IEnumerable<Product> products)
{
// Attach eventhandler for each products PropertyChanged event.
// When the LineTotal property has changed, recalculate the total.
foreach (var p in products)
{
p.PropertyChanged += (sender, e) =>
{
if (e.PropertyName == "LineTotal")
CalculateTotalAmount();
};
}

CalculateTotalAmount();
}

public void CalculateTotalAmount()
{
// Set TotalAmount property to the sum of all line totals.
TotalAmount = Products.Sum(p => p.LineTotal);
}

private decimal _TotalAmount;
public decimal TotalAmount
{
get { return _TotalAmount; }
set
{
if (value != _TotalAmount)
{
_TotalAmount = value;

if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("TotalAmount"));
}
}
}

public event PropertyChangedEventHandler PropertyChanged;
}

public class Product : INotifyPropertyChanged
{
public string Name { get; set; }

private decimal _LineTotal;
public decimal LineTotal
{
get { return _LineTotal; }
set
{
if (value != _LineTotal)
{
_LineTotal = value;

if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("LineTotal"));
}
}
}

public event PropertyChangedEventHandler PropertyChanged;
}

XAML:

<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<DataGrid ItemsSource="{Binding Products}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" />
<DataGridTextColumn Binding="{Binding LineTotal}" />
</DataGrid.Columns>
</DataGrid>

<Button Click="AddItem">Add item</Button>
<Button Click="RemoveItem">Remove item</Button>

<TextBlock>
<Run>Total amount:</Run>
<Run Text="{Binding TotalAmount}" />
</TextBlock>
</StackPanel>
</Window>

关于c# - 通知/绑定(bind)父属性以计算子属性的总和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12691978/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com