有很多方法可以解决这个问题。显然,您可以遍历网格行并计算每行的总数并将所有这些值相加。或者,如果网格有数据源,您可以遍历这些行/项目并获取总数。
因此,由于您没有说明网格是否具有数据源,因此很难提出适当的解决方案。例如,如果网格的基础数据源是DataTable,那么您可以将“总计”“表达式”列“添加”到网格中,以计算每行的“价格”*“数量”值。这将从您的代码中删除一项计算。您还可以使用DataTable 的Compute 函数将文本框文本设置为DataTable 中所有“总计”单元格的总和,从而消除您必须编写的另一个计算。每当网格“价格”或“数量”值发生变化时,我们将使用数据表 Compute 函数更新文本框总和。
或者正如 Mansur 的回答所暗示的,您可以创建一个简单的类来管理网格的数据源以及文本框数据绑定。这是下面使用的方法。在Item 类中,将有三个属性,其中“价格”和“数量”都是“可编辑”属性。第三个属性将是一个只读的“Total”,它将返回“Price”*“Quantity”值。
我们可以简单地创建一个Item 对象的列表,它应该会让事情变得更容易,但是,我说让我们更进一步,创建另一个名为ListOfItems 的类,它将有两个属性。一个BindingList 的Item 对象和一个decimal 只读属性,它返回列表中所有项目的SumTotal。
这个类的想法是我们现在可以将网格和TextBox 绑定到“相同的”DataSource。网格的DataMember 将是Item 对象的BindingList,为了绑定TextBox,我们将其DataMember 设置为SumTotal 属性。就计算每行总数和所有行的总数而言,这应该会使事情变得更容易。
public class Item {
public decimal Price { get; set; }
public int Quantity { get; set; }
public decimal Total => Price * Quantity;
}
public class ListOfItems {
public BindingList<Item> Items { get; set; }
public ListOfItems() {
Items = new BindingList<Item>();
}
public decimal SumTotal => Items.Sum(x => x.Total);
}
但是,有一个小问题。如果我们查看ListOfItems 类......我们可以看到SumTotal 将反映Items 列表的当前状态,但是如果列表发生变化,那么我们仍然需要一些机制来向文本框发出信号以“更新“ 总数。此外,当用户更改网格单元格值时,在某些情况下,网格中的数据可能不一定存在于底层数据源中。在这种情况下,总数可能是错误的。
如果我们简单地使用BindingSource,这些问题(以及其他问题)可以得到解决。如果我们使用BindingSource 并将它的DataSource 设置为ListOfItems 对象,那么当单元格价格或数量发生变化时,我们需要做的就是调用BindingSource 的ResetBinding 方法,它应该会更新网格和文本框一步到位。即使这不是必需的,在网格中使用 BindingSource 也有很多优点……就像这样。
要对此进行测试,您可以创建一个新的 winforms 解决方案,并将一个 DataGridView 和一个 TextBox 放在表单上以表示总和。有两个全局变量……BindingSource 和 ListOfItems 对象。下面的代码是用来生成一些测试数据的。
private ListOfItems GetData() {
ListOfItems listOfItems = new ListOfItems();
listOfItems.Items.Add(new Item { Price = 10.50m, Quantity = 2 });
listOfItems.Items.Add(new Item { Price = 1.0m, Quantity = 3 });
listOfItems.Items.Add(new Item { Price = 1.50m, Quantity = 3 });
return listOfItems;
}
设置一切的加载方法……
BindingSource bs;
ListOfItems AllItems;
public Form1() {
InitializeComponent();
dataGridView1.CellValueChanged += new DataGridViewCellEventHandler(dataGridView1_CellValueChanged);
}
private void Form1_Load(object sender, EventArgs e) {
AllItems = GetData();
bs = new BindingSource();
bs.DataSource = AllItems;
dataGridView1.DataSource = bs;
dataGridView1.DataMember = "Items";
textBox1.DataBindings.Add("Text", bs, "SumTotal");
}
最后,网格CellValueChanged 事件在“价格”或“数量”单元格更改时更新文本框。我们需要做的就是重置要更新的文本框的绑定源。
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
if (dataGridView1.Columns[e.ColumnIndex].Name == "Price" ||
dataGridView1.Columns[e.ColumnIndex].Name == "Quantity") {
if (dataGridView1.Rows[e.RowIndex].Cells["Price"].Value != null &&
dataGridView1.CurrentRow.Cells["Quantity"].Value != null) {
if (!string.IsNullOrWhiteSpace(dataGridView1.CurrentRow.Cells["Price"].FormattedValue.ToString()) &&
!string.IsNullOrWhiteSpace(dataGridView1.CurrentRow.Cells["Quantity"].FormattedValue.ToString())) {
bs.ResetBindings(false);
}
}
}
}
最后,如前所述,您可以使用DataTable 执行相同的操作,方法是将ListOfItems 类的Items 属性更改为DataTable,并使用LINQ 或DataTable 的@ 987654367@ 函数计算总和。在我的测试中,这将需要额外的步骤,但这很简单。
我希望这是有道理的。