Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf DataGrid计算两个数据绑定单元格中的值之间的差值_Wpf_Datagrid_Binding - Fatal编程技术网

Wpf DataGrid计算两个数据绑定单元格中的值之间的差值

Wpf DataGrid计算两个数据绑定单元格中的值之间的差值,wpf,datagrid,binding,Wpf,Datagrid,Binding,在我的小应用程序中,我有一个绑定到测量对象列表的DataGrid(参见屏幕截图)。测量只是一个具有两个属性的数据容器:日期和反气体(浮动)。 每个测量对象代表我在特定日期的耗气量 测量值列表绑定到DataGrid,如下所示: <DataGrid ItemsSource="{Binding Path=Measurements}" AutoGenerateColumns="False"> <DataGrid.Columns>

在我的小应用程序中,我有一个绑定到测量对象列表的DataGrid(参见屏幕截图)。测量只是一个具有两个属性的数据容器:日期和反气体(浮动)。 每个测量对象代表我在特定日期的耗气量

测量值列表绑定到DataGrid,如下所示:

    <DataGrid ItemsSource="{Binding Path=Measurements}" AutoGenerateColumns="False">
        <DataGrid.Columns>
             <DataGridTextColumn Header="Date" Binding="{Binding Path=Date, StringFormat={}{0:dd.MM.yyyy}}" />
             <DataGridTextColumn Header="Counter Gas" Binding="{Binding Path=ValueGas, StringFormat={}{0:F3}}" />
        </DataGrid.Columns>
    </DataGrid>

现在我的问题是:) 我想在“计数器气体”列旁边有另一列,显示实际计数器值和最后一个计数器值之间的差值

例如,此附加列应计算2月13日和2月6日的值之间的差值=>199.789-187.115=15.674

实现这一目标的最佳方式是什么?我想避免在测量类中进行任何计算,这些计算应该只保存数据。我更喜欢DataGrid来处理计算。 那么,有没有一种方法可以添加另一列,只计算to值之间的差异?可能使用某种转换器和极限绑定;D


旁白:也许有个名声更好的人可以嵌入这个截图。谢谢:)

极端绑定?没问题

<Window.Resources>
    <local:ItemsDifferenceConverter x:Key="ItemsDifferenceConverter"/>
</Window.Resources>
<DataGrid ItemsSource="{Binding Path=Measurements}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Date" Binding="{Binding Path=Date, StringFormat={}{0:dd.MM.yyyy}}" />
        <DataGridTextColumn Header="Counter Gas" Binding="{Binding Path=ValueGas, StringFormat={}{0:F3}}" />
        <DataGridTextColumn Header="Difference">
            <DataGridTextColumn.Binding>
                <MultiBinding Converter="{StaticResource ItemsDifferenceConverter}" Mode="OneWay">
                    <Binding Path="."/>
                    <Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGrid}}" Path="ItemsSource"/>
                </MultiBinding>
            </DataGridTextColumn.Binding>
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

非常感谢你!这就像一个符咒:)但正如你所说,有一些缺点。但没问题,这么小的解决方案是gerate的!只是出于兴趣:在这种情况下,您将如何实现中间视图模型?@justMe我在答案的和处添加了我的示例。它使用CollectionView并观察更改。@Vortex:在这种情况下如何实现相同的视图模型?我有一个datagrid,它垂直显示数据库中的一个表,如下所示:分数| 75 | 100。我必须在分数下面添加一个名为Difference的新行,该行应显示或返回值75和100之间的差值。(这只是一个例子)(P.S:差异中没有负值)。。这真的很有帮助。。Thanks@Buba1947如果需要行而不是列,则应向集合中添加新项。像
someCollection.Add(新的SomeModel{Title=“Difference”,Score75=null,Score100=(scoresItem.Score100-scoresItem.Score75)})。我想如果你为你想要的表格做一个屏幕截图,然后再做一个单独的问题会更好。@vortex:我已经把这个问题贴在这里了。有空的时候请看一看。非常感谢。
class ItemsDifferenceConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType,
                      object parameter, CultureInfo culture)
    {
        if (values.Length != 2)
            return null;

        var item = values[0] as Measurement;
        var collection = values[1] as IEnumerable<Measurement>;
        if (item == null || collection == null)
            return null;

        var list = collection.OrderBy(v => v.Date).ToList(); //it will be easier to find a previous date
        var itemIndex = list.IndexOf(item);
        if (itemIndex == 0) //First item
            return null;

        var diff = item.ValueGas - list[itemIndex - 1].ValueGas;
        return (diff > 0 ? "+" : "") + diff.ToString();
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new Exception("The method or operation is not implemented.");
    }
}
/// <summary>
/// Main ViewModel, contains items for DataGrid
/// </summary>
public class MeasurementListViewModel
{
    public MeasurementListViewModel(IEnumerable<Measurement> measurements)
    {
        this.Items = new ObservableCollection<MeasurementViewModel>(measurements.Select(m=>new MeasurementViewModel(m)));
        this.Measurements = (ListCollectionView)CollectionViewSource.GetDefaultView(this.Items);

        this.Items.CollectionChanged += new NotifyCollectionChangedEventHandler(Items_CollectionChanged);
        foreach(var m in this.Items)
            m.PropertyChanged += new PropertyChangedEventHandler(Item_PropertyChanged);

    }

    //Date or Value were changed
    void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        //Update the collection view if refresh isn't possible
        if (this.Measurements.IsEditingItem)
            this.Measurements.CommitEdit();
        if (this.Measurements.IsAddingNew)
            this.Measurements.CommitNew();

        this.Measurements.Refresh();
    }

    //Items were added or removed
    void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        //Attach the observer for the properties
        if (e.NewItems != null)
            foreach (var vm in e.NewItems.OfType<MeasurementViewModel>())
                vm.PropertyChanged += Item_PropertyChanged;

        //Refresh when it is possible
        if(!this.Measurements.IsAddingNew && !this.Measurements.IsEditingItem)
            this.Measurements.Refresh();
    }

    private ObservableCollection<MeasurementViewModel> Items { get; set; }

    public ListCollectionView Measurements { get; set; }
}

/// <summary>
/// Wraps Measurement class and provide notification of changes
/// </summary>
public class MeasurementViewModel
{
    public MeasurementViewModel()
    {
        this.Model = new Measurement();
    }

    public MeasurementViewModel(Measurement m)
    {
        this.Model = m;
    }

    public Measurement Model { get; private set; }

    public DateTime Date
    {
        get { return this.Model.Date; }
        set
        {
            this.Model.Date = value;
            OnPropertyChanged("Date");
        }
    }

    public double ValueGas
    {
        get { return this.Model.ValueGas; }
        set
        {
            this.Model.ValueGas = value;
            OnPropertyChanged("ValueGas");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
class ItemsDifferenceConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType,
                      object parameter, CultureInfo culture)
    {
        var item = values[0] as MeasurementViewModel;
        var view = values[1] as ICollectionView;
        if (item == null || view == null)
            return null;

        var list = view.SourceCollection.OfType<MeasurementViewModel>().OrderBy(v => v.Date).ToList(); //it will be easier to find a previous date
        var itemIndex = list.IndexOf(item);

        if (itemIndex == 0) //First item
            return null;

        var diff = item.ValueGas - list[itemIndex - 1].ValueGas;
        return (diff > 0 ? "+" : "") + diff.ToString();
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new Exception("The method or operation is not implemented.");
    }
}
<DataGrid ItemsSource="{Binding Path=Measurements}"  AutoGenerateColumns="False"
          CanUserAddRows="True">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Date" Binding="{Binding Path=Date, StringFormat={}{0:dd.MM.yyyy}}" />
        <DataGridTextColumn Header="Counter Gas" Binding="{Binding Path=ValueGas, StringFormat={}{0:F3}}" />
        <DataGridTextColumn Header="Difference">
            <DataGridTextColumn.Binding>
                <MultiBinding Converter="{StaticResource ItemsDifferenceConverter}" Mode="OneWay">
                    <Binding Path="."/>
                    <Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGrid}}" Path="ItemsSource"/>
                </MultiBinding>
            </DataGridTextColumn.Binding>
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>