DataGrid计算列

5

我正在尝试将我的Excel应用转移到WPF数据网格。我将输入数据到A列中,并在B列中进行计算,取A列的上一个单元格和当前单元格,并添加B列的上一个单元格。

计算示例:B2 = B1 +(A2-A1)。最好的方法是什么?


稍等,我刚刚注意到了。你所说的“前一个单元格”,是指上一行的单元格吗? - Jacob Proffitt
是的,同一列的上一行单元格。当前行为2,因此在单元格(B2)中,我想进行计算= B1 +(A2-A1)。 - Jim
2个回答

4
最好的方法是在一个类中实现这个逻辑,并将网格绑定到相应的属性。例如:
class SomeData 
{
  int A { get; set; }
  int B { get; set; }
  int AminusB { get { return A - B; } }
}

1
这个确切的解决方案无法完成所需的任务。每个SomeData实例都必须引用前一个SomeData,以便每次根据前一个SomeData上的A和B的值计算B。 - Adam Gritt
亚当,你发现得真好。我在回答中也忽略了那个问题。 - Jacob Proffitt
谢谢,我已经成功实现了你们的解决方案(Nick和Jacob),可以在同一行上进行计算而没有任何问题。然而,我仍然不明白如何获取前一行的单元格并将其添加到当前行的单元格中 B2 = B1 + (A2-A1)。 - Jim

4

个人建议,先创建一个代表记录的类,并在该类上实现INotifyPropertyChanged接口。

public class recordObject : INotifyPropertyChanged
{
    private int a;
    public int A 
    { 
        get
        {
            return a;
        }
        set
        {
            a = value;
            OnPropertyChanged("A");
        }
    }

    private int b;
    public int B
    { 
        get
        {
            return b;
        }
        set
        {
            b = value;
            OnPropertyChanged("B");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

然后,在显示数据网格的窗口的代码后台中,您将需要订阅列表中每个对象的PropertyChanged。每当这些属性更改时,您就必须手动计算列值。我知道很糟糕,但它会起作用。

属性更改事件应如下所示:

void recordObject_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    var objectList = DataGrid.ItemsSource as List<recordObject>;
    var myRecord = sender as recordObject;
    if (objectList != null && myRecord != null)
    {
        int idx = objectList.IndexOf(myRecord);
        // Perform your calculations here using idx to access records before and after the current record
        // making sure to check for list boundaries for top and bottom.
        // Also note that this will likely kick off cascading event calls so make sure you're only changing
        // the previous or following record object.
    }
}

如果您将此事件挂钩到绑定列表中的所有记录上,则每当更改任何属性时,它都会触发。在上面的类中,这将适用于A和B。您可以通过e.PropertyName(简单字符串比较)过滤出您感兴趣的要监视的属性,并相应地计算业务逻辑。如果您想保持封装性,或者至少将对象的业务逻辑放在对象本身上,那么该方法可以是类recordObject的静态方法。但是,您需要提供一种从该静态方法获取datagrid的方法(可能是通过窗口上的静态属性)。所以:
public static void recordObject_PropertyChanged(object sender, PropertyChangedEventArgs e)

并连接如下:
record.PropertyChanged += new PropertyChangedEventHandler(recordObject.recordObject_PropertyChanged);

哇,这是非常详细的答案,谢谢。就我所理解的而言,您的答案侧重于自动更新B列,这是受欢迎的,但目前不是我所需要的。我现在正在寻找的是幕后的业务逻辑。 - Jim
1
我会标记它为已回答,但是我需要学习你建议的东西并进行大量尝试和错误。 - Jim
回复您的评论,我对您在代码中做的笔记非常感兴趣(例如...// 在此处使用idx执行计算...可能会引发级联事件等)。理想情况下,我会将该逻辑放在recordObject中,但似乎不可能。 - Jim
不是不可能的。只需要在窗口上创建一个静态 DataGrid 属性,并在 Window_Loaded 中将你的 datagrid 分配给它。这样,你可以引用你的对象集合作为 MyWindow.MyDataGrid.ItemsSource。 - Jacob Proffitt
谢谢,我已经成功创建了一个静态的DataGrid属性,并在我的对象中引用它,但是当我在我的DataGrid中添加新行时,这个事件根本没有触发。这是很自然的,因为新对象没有与record.PropertyChanged连接起来。那么,即使通过DataGrid输入而不是以编程方式创建新对象,我应该如何正确地连接它呢? - Jim
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接