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)。但在代码中并不难做到:
事件驱动计算
与给出的DGVCellFormatting
答案类似,您可以从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