I've a application with a datagrid in WPF with C#, I've 4 columns, and I need that the four column is calculated with respect to the other columns. I use IValueConverter, that works perfectly, but only calculates values of the column four when I change the row, and I need that when I change the cell 2 and 3, changes the 4 column.
This is my XAML:
<Window x:Class="WpfApplication6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication6"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid Name="grid">
<DataGrid.Resources>
<local:CalculatingConverter x:Key="CalculatingConverter" />
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" />
<DataGridTextColumn Binding="{Binding Count}"/>
<DataGridTextColumn Binding="{Binding Price}" />
<DataGridTextColumn
Header="Total"
Binding="{Binding Converter={StaticResource CalculatingConverter}}"
/>
</DataGrid.Columns>
</DataGrid>
</Grid>
This is my code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<Item> items = new List<Item>();
items.Add(new Item() { Name = "Item1", Count = 2, Price = 10 });
items.Add(new Item() { Name = "Item2", Count = 5, Price = 20 });
this.grid.ItemsSource = items;
}
}
public class Item : INotifyPropertyChanged
{
private string name;
private decimal price;
private int count;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string Name {
get
{
return this.name;
}
set
{
if (value != name)
{
name = value;
OnPropertyChanged();
}
}
}
public decimal Price
{
get
{
return price;
}
set
{
if (value != this.Price)
{
price = value;
OnPropertyChanged();
}
}
}
public int Count {
get
{
return count;
}
set
{
if (value != count)
{
count = value;
OnPropertyChanged();
}
}
}
public decimal TotalPrice
{
get { return Price * Count; }
}
}
And this is my IConverter:
public class CalculatingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
return ((Item)value).Price * ((Item)value).Count;
}
catch
{
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
How can I do it?
Your Item
class needs to implement INotifyPropertyChanged
and raise the PropertyChanged
event when any of its properties changes.
The trouble then is that there's no way for that binding to know what properties it needs to be watching for changes. One solution to that is to change your converter to IMultiValueConverter
and change that binding to a MultiBinding
which explicitly binds both Price
and Count
.
Another option for you, and this would be a much simpler option, would be to add a read only TotalPrice
property to your Item
class. That's what I would do.
public decimal TotalPrice {
get { return Price * Count; }
}
Then, in your Price
property, when Price
changes, you would raise the PropertyChanged
event for TotalPrice
as well as for Price
. And you would do the same for Count
.
Then you could bind to TotalPrice
very simply in the XAML with no converter at all. You might need to make the binding Mode=OneWay
, since it's read only.
Let me know if you need more code examples.
You have to use a IValueConverter
for this. Use first column as your source (bind second column to first) and convert the value using your converter.
Finally thanks to Ed Plunkett i implement INotifyPropertyChanged
in my item
class and in Price
and Count
force to call to OnPropertyChanged("TotalPrice")
and works perfectly:
public class Item : INotifyPropertyChanged
{
private string name;
private decimal price;
private int count;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string Name {
get
{
return this.name;
}
set
{
if (value != name)
{
name = value;
OnPropertyChanged();
}
}
}
public decimal Price
{
get
{
return price;
}
set
{
if (value != this.Price)
{
price = value;
OnPropertyChanged();
OnPropertyChanged("TotalPrice");
}
}
}
public int Count {
get
{
return count;
}
set
{
if (value != count)
{
count = value;
OnPropertyChanged();
OnPropertyChanged("TotalPrice");
}
}
}
public decimal TotalPrice
{
get { return Price * Count; }
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.