将公式单元格应用于DataGridview

时间:2016-08-09 13:38:46

标签: c# winforms datagridview formula

我想在DataGridView中添加公式单元格。是否有任何自定义DataGridView来执行此操作?

示例:

grid[4, column].Text = string.Format("=MAX({0}6:{0}{1})", columnAsString, grid.RowCount);

4 个答案:

答案 0 :(得分:7)

在很多情况下,很多情况下数据实际上并不在public static IWebElement WaitAndFindElement(Func<IWebDriver, IWebElement> expectedCondtions, int timeoutInSeconds) { WebDriverWait webDriverWait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds)); return webDriverWait.Until(expectedCondtions); } //Now you can call above function as IWebElement el = WaitAndFindElement(ExpectedConditions.ElementExists(by), timeoutInSeconds); 中,而在其他地方如IWebElement el = WaitAndFindElement(ExpectedConditions.elementToBeClickable(by), timeoutInSeconds); 或某种类型的集合(如DataGridView)。控件只是向用户显示数据视图。

有几种方法可以按照你想要的方式做某事。对于这两种情况,数据实际上都位于DataTable

表达式

可以为List<T>分配Expression。请参阅链接,了解所支持的表达式,关键字,运算符和函数的类型。以下内容将为某些行创建基于表达式的列到多个DataTable

DataColumn

添加一些随机数据后,以及一个空行,Quantity * Price将为您维护这些列。这可能就像您可能希望的那样:如果用户(或代码)更改了dtSample = new DataTable(); dtSample.Columns.Add(new DataColumn("Item", typeof(string))); dtSample.Columns.Add(new DataColumn("Quantity", typeof(int))); dtSample.Columns.Add(new DataColumn("Price", typeof(decimal))); dtSample.Columns.Add(new DataColumn("Sale", typeof(decimal))); // assign expression using the col names dtSample.Columns[3].Expression = "(Quantity * Price)"; DataTable单元格的值,则Quantity列内容会自动更新。 (图像在第二种方法之后)。

Price在行级别工作。对于像TOTALS行这样的东西,没有全行/逐表的计数器部分 - 这是因为数据通常来自Sale。添加计算的行可能会意外地将新数据添加到该源(如数据库)。但是在代码中做起来并不难:

事件驱动的计算

与给出的DGV Expressions答案类似,您可以回复来自DataSource的事件,例如CellFormatting。在那里,您可以执行任何操作并更新表格。

DataTable

然后,在该事件中,代码计算在最后一行中显示的超过所有单位平均值。在某些情况下,您可以使用RowChanged的{​​{1}}方法。与...create table and columns ...populate table // hook up event dtSample.RowChanged += RowChanged; 不同,它不会自动更新,as shown in this answer更新可能会很笨拙。

使用DataTable中的类型化数据,可以非常轻松地执行计算以响应事件:

Compute()

enter image description here

“销售”列通过DataTable自动维护,这意味着您无法手动对该列执行任何操作。

底部的整体平均价格也“自动”更新,不同之处在于我们必须编写一些代码才能这样做。

答案 1 :(得分:3)

是否有任何自定义DataGridView可以执行此操作?

偏离主题,但如果您正在寻找自定义控件,请查看Free .NET Spreadsheet Control。它还支持formula

如果您可以选择编写计算代码

如果编写用于计算的代码是您的选项,要根据某些其他单元格的值计算单元格的值,您可以使用CellFormatting事件DataGridView并将计算逻辑放在那里。同时处理CellEndEdit并致电InvalidateCellInvalidate以强制更新参考单元格中每个单元格后的值。

以下是一个例子:

void Form1_Load(object sender, EventArgs e)
{
    Random r = new Random();
    var dt = new DataTable();
    dt.Columns.Add("A", typeof(int));
    dt.Columns.Add("B", typeof(int));
    for (int i = 0; i < 10; i++)
        dt.Rows.Add(r.Next(100));
    grid.DataSource = dt;
    grid.CellFormatting += grid_CellFormatting;
    grid.CellEndEdit += grid_CellEndEdit;
}
void grid_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    grid.Invalidate();
}
void grid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    var grid = sender as DataGridView;
    var parameterColumnName = "A";       //Parameter column name
    var start = 0;                       //Start row index for formula
    var end = grid.RowCount - 1;         //End row index for formula
    var resultRowIndex = 0;              //Result row index
    var resultColumnName = "B";          //Result column name
    if (e.RowIndex == resultRowIndex &&
        grid.Columns[e.ColumnIndex].Name == resultColumnName)
    {
        var list = Enumerable.Range(start, end - start + 1)
              .Select(i => grid.Rows[i].Cells[parameterColumnName].Value)
              .Where(x => x != null && x != DBNull.Value)
              .Cast<int>();
        if (list.Any())
            e.Value = list.Max();
    }
}

注意

解决方案不仅限于DataTable,无论您使用DataSource DataGridView,它都可以使用,您可以在此解决方案中使用任何类型的数据源。

答案 2 :(得分:2)

不,您正在处理纯数据字符串,您需要在后台运行一个线程来进行计算并相应地更新UI。

答案 3 :(得分:0)

您可以尝试的几件事:

处理单元格值更改事件,以检测计算中使用的单元格之一何时更改并计算适当的值。诸如此类(在新项目中尝试)

Public Class Form1
  Private WithEvents DGV As New DataGridView
  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    DGV.SetBounds(20, 50, 400, 200)
    Controls.Add(DGV)
    DGV.Columns.Add("Qty", "Qty")
    DGV.Columns.Add("Price", "Price")
    DGV.Columns.Add("Total", "Total")
    DGV.Columns("Total").ReadOnly = True
    DGV.RowCount = 5
  End Sub

  Private Sub DGV_CellValueChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DGV.CellValueChanged
    If e.ColumnIndex = DGV.Columns("Qty").Index Or e.ColumnIndex = DGV.Columns("Price").Index Then
      DGV("Total", e.RowIndex).Value = CInt(DGV("Qty", e.RowIndex).Value) * CDbl(DGV("Price", e.RowIndex).Value)
    End If
  End Sub
End Class

或者不是直接将文件读取到datagridview而是将其读入数据表并将网格绑定到数据表。然后,您可以在数据表中添加一个表达式列以进行计算。像这样:

Public Class Form1
  Private WithEvents DGV As New DataGridView
  Private DT As New DataTable
  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    DGV.SetBounds(20, 50, 400, 200)
    Controls.Add(DGV)
    DT.Columns.Add("Qty", GetType(Int32))
    DT.Columns.Add("Price", GetType(Double))
    DT.Columns.Add("Total", GetType(Double))
    DT.Columns("Total").Expression = "Qty * Price"
    DGV.DataSource = DT
  End Sub
End Class