简体   繁体   English

DataGrid WPF中的计算列

[英]Calculated column in datagrid WPF

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. 我有一个带有C#的WPF中具有数据网格的应用程序,我有4列,我需要相对于其他列计算这4列。 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. 我使用IValueConverter,它工作正常,但仅在更改行时计算第四列的值,并且在更改单元格2和3时需要更改第4列。

This is my XAML: 这是我的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: 这是我的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. 您的Item类需要实现INotifyPropertyChanged并在其任何属性更改时引发PropertyChanged事件。

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 . 一种解决方案是将您的转换器更改为IMultiValueConverter ,并将该绑定更改为一个显式绑定PriceCountMultiBinding

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. 对您来说,这是一个更简单的选择,它是向您的Item类添加一个只读的TotalPrice属性。 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 . 然后,在Price属性中,当Price变化时,您将引发TotalPricePricePropertyChanged事件。 And you would do the same for Count . 您也可以对Count做同样的事情。

Then you could bind to TotalPrice very simply in the XAML with no converter at all. 然后,您可以在XAML中非常简单地绑定到TotalPrice ,而无需任何转换器。 You might need to make the binding Mode=OneWay , since it's read only. 您可能需要设置绑定Mode=OneWay ,因为它是只读的。

Let me know if you need more code examples. 让我知道您是否需要更多代码示例。

You have to use a IValueConverter for this. 您必须为此使用IValueConverter Use first column as your source (bind second column to first) and convert the value using your converter. 将第一列用作源(将第二列绑定到第一列),然后使用转换器转换值。

MSDN example . MSDN示例

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: 最后,感谢Ed Plunkett,我在我的item类中实现了INotifyPropertyChanged ,并在Price and Count实现了对OnPropertyChanged("TotalPrice")调用,并且效果很好:

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;  }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM