Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/317.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
C# 将公式单元格应用于DataGridview_C#_Winforms_Datagridview_Formula - Fatal编程技术网

C# 将公式单元格应用于DataGridview

C# 将公式单元格应用于DataGridview,c#,winforms,datagridview,formula,C#,Winforms,Datagridview,Formula,我想在DataGridView中添加公式单元格。是否有任何自定义的DataGridView来执行此操作 例如: grid[4, column].Text = string.Format("=MAX({0}6:{0}{1})", columnAsString, grid.RowCount); 不,您正在处理纯数据字符串,您需要在后台运行一个线程来执行计算并相应地更新UI。是否有自定义DataGridView来执行此操作? 主题外,但如果您正在寻找自定义控件,请查看。它还支持 如果您可以选择编写计

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

例如:

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

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

是否有自定义DataGridView来执行此操作?

主题外,但如果您正在寻找自定义控件,请查看。它还支持

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

如果您可以选择编写计算代码,则要根据其他单元格的值计算单元格的值,可以使用
DataGridView
CellFormatting
事件并将计算逻辑放在那里。还要处理
CellEndEdit
并调用
InvalidateCell
Invalidate
以强制更新参考单元格中每个单元格后面的单元格值

以下是一个例子:

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();
    }
}
void Form1\u加载(对象发送方,事件参数e)
{
随机r=新随机();
var dt=新数据表();
添加(“A”,类型(int));
添加(“B”,类型(int));
对于(int i=0;i<10;i++)
dt.Rows.Add(r.Next(100));
grid.DataSource=dt;
grid.CellFormatting+=网格\u CellFormatting;
grid.CellEndEdit+=grid_CellEndEdit;
}
void grid_CellEndEdit(对象发送方,DataGridViewCellEventArgs e)
{
grid.Invalidate();
}
void grid_CellFormatting(对象发送方、DataGridViewCellFormattingEventArgs e)
{
var grid=发送方作为DataGridView;
var parameterColumnName=“A”;//参数列名
var start=0;//开始公式的行索引
var end=grid.RowCount-1;//结束公式的行索引
var resultRowIndex=0;//结果行索引
var resultColumnName=“B”;//结果列名
如果(e.RowIndex==resultRowIndex&&
grid.Columns[e.ColumnIndex].Name==resultColumnName)
{
变量列表=可枚举范围(开始,结束-开始+1)
.Select(i=>grid.Rows[i].Cells[parameterColumnName].Value)
.Where(x=>x!=null&&x!=DBNull.Value)
.Cast();
if(list.Any())
e、 Value=list.Max();
}
}
注意


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

在许多情况下,数据实际上并不在
DataGridView
中,但在其他地方,如
数据表
或某种集合(如
列表
)。控件只是向用户显示数据的视图

有几种方法可以按照你想要的去做。对于这两种情况,数据实际上驻留在
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
将为您维护这些列。这就像您可能希望的那样:如果用户(或代码)更改
数量
价格
单元格的值,则
销售
列内容将自动更新。(第二种方法之后是图像)

表达式
在行级别工作。对于TOTALS行这样的行,没有一个all rows/table-wise计数器部分——这是因为数据通常来自
数据源。添加计算行可能会意外地将新数据添加到该源(如DB)。但在代码中并不难做到:

事件驱动计算 与给出的DGV
CellFormatting
答案类似,您可以从
DataTable
响应事件,例如
RowChanged
。在那里,您可以执行任何操作并更新表

...create table and columns
...populate table
// hook up event
dtSample.RowChanged += RowChanged;
然后,在该事件中,代码计算要显示在最后一行中的总体单位平均值。在某些情况下,您可以使用
DataTable
Compute()
方法。与
表达式不同的是,它不是自动更新的,而且更新起来可能会很笨拙

对于DataTable中的类型化数据,响应事件执行计算相当容易:

private void RowChanged(object sender, DataRowChangeEventArgs e)
{
    // number of rows used 
    int Rows = dtSample.Rows.Count-1;
    if (e.Row == dtSample.Rows[Rows]) return;

    // display TotalSales / TotalUnits
    // get the units
    int TotUnits = dtSample
        .AsEnumerable()
        .Where(r => !r.IsNull("Quantity"))
        .Take(Rows)
        .Sum(n => n.Field<int>("Quantity"));
    
    // sum Sales, divide and display in DGV
    dtSample.Rows[Rows]["Price"] = dtSample
        .AsEnumerable()
        .Where(r => !r.IsNull("Sale"))
        .Take(Rows)
        .Sum(n => n.Field<decimal>("Sale")) / TotUnits;
}
private void行已更改(对象发送方,DataRowChangeEventArgs e)
{
//使用的行数
int Rows=dtSample.Rows.Count-1;
if(e.Row==dtSample.Rows[Rows])返回;
//显示总销售额/总单位
//拿到单位
int TotUnits=dtSample
.可计算的()
.其中(r=>!r.IsNull(“数量”))
.Take(行)
.Sum(n=>n.字段(“数量”);
//在DGV中求和销售、分割和显示
dtSample.Rows[行][“价格”]=dtSample
.可计算的()
.其中(r=>!r.IsNull(“销售”))
.Take(行)
.Sum(n=>n.Field(“销售”)/tot单位;
}

“Sales”列通过
表达式自动维护,这意味着您无法手动对该列执行任何操作


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

您可以尝试以下几种方法:

处理“单元格值更改”事件,以检测计算中使用的其中一个单元格何时更改并计算适当的值。类似这样的内容(在新项目中尝试)

或者,与其将文件直接读取到datagridview,不如将其读入datatable并将网格绑定到datatable。然后可以在datatable中添加一个表达式列来进行计算。大概是这样的:

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
如果你
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