我无法理解如何将UI上的总销售文本框绑定到数据网格中总价格的总和。我已经阅读了几篇文章,试图实现一个总和程序并绑定它,尝试使用集合更改通知,我无法让总销售工作。我有一个具有Quantity和UnitPrice属性的项目类,其计算的TotalPrice会在数量或单价变化时自动更新。项目列表包含在SalesOrder类中。 ui是我用来创建订单的主窗口。 我的代码位于:https://github.com/battondl/SalesOrder/tree/master/simpleShoppingListProgram 有关如何让UI文本框中的总价格自动更新的任何指导将非常感激。
数据网格中的每个订单项都具有基于数量*单价的总价格。
这是我想要更新的总销售价格,它是所有订单项总价的总和。
class Item : INotifyPropertyChanged
{
private string partNumber;
private int quantity;
private decimal unitPrice;
private DateTime orderDate;
public string PartNumber
{
get { return partNumber; }
set
{
partNumber = value;
OnPropertyChanged();
}
}
public int Quantity
{
get { return quantity; }
set
{
quantity = value;
OnPropertyChanged("Quantity");
OnPropertyChanged("TotalPrice");
}
}
public decimal UnitPrice
{
get { return unitPrice; }
set
{
unitPrice = value;
OnPropertyChanged("UnitPrice");
OnPropertyChanged("TotalPrice");
}
}
public DateTime OrderDate
{
get { return orderDate; }
set
{
orderDate = value;
OnPropertyChanged();
}
}
public decimal TotalPrice => Quantity * UnitPrice;
public Item()
{
PartNumber = "";
Quantity = 0;
UnitPrice = 0.00m;
OrderDate = DateTime.Now;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string caller = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
}
}
class SalesOrder
{
private string orderNumber;
public string OrderNumber
{
get { return orderNumber; }
set
{
orderNumber = value;
}
}
private ObservableCollection<Item> items;
public ObservableCollection<Item> Items
{
get { return items; }
}
public SalesOrder()
{
orderNumber = "";
items = new ObservableCollection<Item>();
}
public decimal CalculateTotalPrice()
{
decimal total = 0.00m;
foreach (Item item in items)
{
total += item.TotalPrice;
}
return total;
}
}
public partial class MainWindow : Window
{
private SalesOrder salesOrder;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
salesOrder = new SalesOrder();
dgSaleItems.ItemsSource = salesOrder.Items;
tbx_totalSale.Text = salesOrder.CalculateTotalPrice().ToString();
}
}
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="6*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical"
Grid.Row="0">
<StackPanel Orientation="Horizontal">
<Label Content="OrderNumber: " />
<TextBox Name="tbx_orderNumber"
Width="100"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical"
Grid.Row="1">
<DataGrid Name="dgSaleItems"
Grid.Row="1"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn x:Name="partNumber"
Header="Part Number"
Binding="{Binding Path=PartNumber}" />
<DataGridTextColumn x:Name="quantity"
Header="Quantity"
Binding="{Binding Path=Quantity}" />
<DataGridTextColumn x:Name="unitPrice"
Header="Unit Price"
Binding="{Binding Path=UnitPrice}" />
<DataGridTextColumn x:Name="totalPrice"
Header="Total Price"
Binding="{Binding Path=TotalPrice}" />
<DataGridTemplateColumn x:Name="orderDate"
Header="Order Date">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=OrderDate}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding Path=OrderDate}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
<StackPanel Orientation="Vertical"
Grid.Row="7">
<StackPanel Orientation="Horizontal">
<Label Content="Total Sale: " />
<TextBox x:Name="tbx_totalSale"
Width="100"/>
</StackPanel>
</StackPanel>
</Grid>
答案 0 :(得分:0)
文本框中没有任何约束:
<TextBox x:Name="tbx_totalSale"
Width="100"/>
需要:
<TextBox x:Name="tbx_totalSale"
Text="{Binding TotalSale}"
Width="100"/>
并且您需要向TotalSale
类添加SaleOrder
属性,以返回行的总和:
public decimal TotalSale
{
get { return items.Sum(i => i.TotalPrice);
}
当在集合中添加或删除项目时,或者当行OnPropertyChanged("TotalSale")
更改时,您需要发布TotalPrice
事件。当数量或单价发生变化时,您已经在更新TotalPrice
,因此您需要做的就是通过items
集合向上传播更改。
答案 1 :(得分:0)
private void Window_Loaded(object sender, RoutedEventArgs e) { salesOrder = new SalesOrder(); dgSaleItems.ItemsSource = salesOrder.Items; tbx_totalSale.Text = salesOrder.CalculateTotalPrice().ToString(); }
您只是在窗口加载事件期间更新总销售额,但是您忘记了每次更改商品的数量或价格时都必须更新它。
以下是你如何做到这一点:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
salesOrder = new SalesOrder();
dgSaleItems.ItemsSource = salesOrder.Items;
salesOrder.Items.CollectionChanged += (s, args) =>
{
if (args.Action == NotifyCollectionChangedAction.Remove)
{
foreach (Item item in args.OldItems)
{
item.PropertyChanged -= UpdateTotalSale;
}
}
else if (args.Action == NotifyCollectionChangedAction.Add)
{
foreach (Item item in args.NewItems)
{
item.PropertyChanged += UpdateTotalSale;
}
}
};
}
private void UpdateTotalSale(object sender, PropertyChangedEventArgs e)
{
tbx_totalSale.Text = salesOrder.CalculateTotalPrice().ToString();
}
理想情况下,您应该在INPC
上实施SalesOrder
,并将上述代码移到SalesOrder
中,因为后面的代码应尽可能保持干净。
答案 2 :(得分:0)
谢谢,我现在就开始工作了!
我已将修改/添加到SalesOrder类
public decimal TotalSale
{
get { return items.Sum(i => i.TotalPrice); }
}
public SalesOrder()
{
orderNumber = "";
items = new ObservableCollection<Item>();
Items.CollectionChanged += (s, args) =>
{
if (args.Action == NotifyCollectionChangedAction.Remove)
{
foreach (Item item in args.OldItems)
{
item.PropertyChanged -= UpdateTotalSale;
}
}
else if (args.Action == NotifyCollectionChangedAction.Add)
{
foreach (Item item in args.NewItems)
{
item.PropertyChanged += UpdateTotalSale;
}
}
};
}
private void UpdateTotalSale(object sender, PropertyChangedEventArgs e)
{
foreach (Window window in Application.Current.Windows)
{
if (window.GetType() == typeof(MainWindow))
{
(window as MainWindow).tbx_totalSale.Text = CalculateTotalPrice().ToString();
}
}
}
我还在xaml中添加了以下内容。
<StackPanel Orientation="Vertical"
Grid.Row="7">
<StackPanel Orientation="Horizontal">
<Label Content="Total Sale: " />
<TextBox x:Name="tbx_totalSale"
Text="{Binding TotalSale}"
Width="100"
x:FieldModifier="public"/>
</StackPanel>
最后,这对于背后的代码:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
salesOrder = new SalesOrder();
dgSaleItems.ItemsSource = salesOrder.Items;
}