c# - 如何将项目列表添加到多列 DataGridView?
问题描述
在我的程序中,我将来自两个 TextBox 控件的输入存储在两个单独的列表中,我将使用它们来填充 DataGridView。
除了在列表中存储文本框值之外,我实际上还没有添加任何代码:
List<string> lTypes = new List<string>();
List<int> lAmounts = new List<int>();
private void btnAddItemL_Click(object sender, EventArgs e)
{
lTypes.Add(txtItemL.Text);
lAmounts.Add(int.Parse(txtAmountL.Text));
}
我有两个单独的列作为“类型”(由 填充lTypes
)和“金额”(由 填充lAmounts
)。
如何使列表分别填充它们各自的列?
解决方案
一种可能的情况:
- 两个 TextBox 控件用于输入一些数据,一个
string
值和一个int
值。 - 数据应存储并显示在 DataGridView 中。
- 目前尚不清楚其他控件是否参与、共享相同的数据或可以修改它:让我们假设其他一些控件现在或将来可能愿意参与。
- 数据可能需要在某个时候进行序列化,或永久存储。
- 数据也可以在不同的用户界面中呈现。
现在,您使用两个List<T>
作为存储(在T
一种string
情况下,int
在另一种情况下),然后在 DataGridView 中显示列表的内容,当然在两个不同的列中。
此设置不完全满足要求:DataGridView 最好由同质数据源提供服务,按列和行组织。
► 当然要注意,我们可以使用 DataGridView 控件本身来输入和编辑数据。有时它很实用,有时则不然。评估。无论如何,用作 DataSource 的对象集合需要支持它。
我们可以使用与所需数据类型匹配的属性来构建一个类对象来存储数据。
此外,在处理数据的 UI 表示时,最好使用框架提供的 DataBinding 功能:它使一切变得更加线性。
在 WinForms 中,BindingList和BindingSource对象提供了许多开箱即用的功能,如数据和数据绑定更改事件、自动货币管理等,允许同步所有需要共享数据源的 UI 元素。
我们只需要构建一个可以描述我们的数据的对象,生成这些数据对象的列表(使用 BindingList)并使用 BindingSource 将所有 UI 元素绑定到该列表。BindingSource 可用作公开DataSource属性(作为 DataGridView)的控件和使用DataBindings的控件的数据源。
基本单位对象:
public class StorageObject
{
public StorageObject() { }
public StorageObject(string type, int amount)
{
this.StorageType = type;
this.Amount = amount;
}
public string StorageType { get; set; }
public int Amount { get; set; }
}
让我们构建一个Manager对象,该对象公开我们需要设置 DataBindings 的实体:
- 此类对象处理
BindingList<StorageObject>
链接到 BindingList 的一个和一个 BindingSource,它提供我们的控件共享和呈现数据所需的数据绑定,以及添加新对象或编辑/更新现有对象。 - 该类还公开了几个方法,这些方法允许以受控方式从数据源中添加或删除数据单元(此处简化以演示该功能)。
该类MyStorage
在存储单元和需要使用每个单元保存的数据的 UI 元素之间提供了一个层。
使用这个类对象,我们可以设置我们需要的数据绑定:
- 将 DataGridView 的 DataSource 设置为 BindingSource。
- 创建两个绑定以将两个 TextBox 控件绑定到同一个源(您在右侧、
Current
面板内、动画中看到的那些)。 - 添加另外两个(未绑定的)TextBox 控件来输入数据(您在动画底部看到的那些)。
public partial class SomeForm : Form
{
private MyStorage myStorage = null;
public SomeForm() {
InitializeComponent();
myStorage = new MyStorage();
myDataGridView.DataSource = myStorage.StorageSource;
txtCurrentType.DataBindings.Add("Text", myStorage.StorageSource, "StorageType", false, DataSourceUpdateMode.OnPropertyChanged);
txtCurrentAmount.DataBindings.Add("Text", myStorage.StorageSource, "Amount", true, DataSourceUpdateMode.OnPropertyChanged);
}
}
要StorageObject
手动添加对象集合,请使用视觉示例中所示的 Button(在动画中,txtType
并且txtAmount
是底部的两个 TextBox 控件,靠近Add...
Button):
private void btnAddStorageObject_Click(object sender, EventArgs e)
{
if (int.TryParse(txtAmount.Text, out int amount) && txtType.TextLength > 0) {
myStorage.Add(txtType.Text, amount);
}
}
要从集合中删除对象,请使用 Button:
private void btnRemoveCurrent_Click(object sender, EventArgs e)
{
// Remove the object that is Current in the BindingSource
myStorage.Remove(myStorage.StorageSource.Current as StorageObject);
// Or, pick one or the other
if (int.TryParse(txtCurrentAmount.Text, out int amount)) {
myStorage.Remove(txtCurrentType.Text, amount);
}
}
您可以将MyStorage
对象传递给另一个表单,并以在该上下文中有意义的任何方式呈现、编辑或以其他方式使用它指向的数据:(
是InputDialog
一个表单,如视觉示例中所示。向接受的表单添加一个构造函数aBindingSource
作为参数)
private void btnUseDialog_Click(object sender, EventArgs e)
{
var inputDialog = new InputDialog(myStorage.StorageSource);
inputDialog.ShowDialog();
}
就这样。如果我们需要绑定其他的Controls,我们只需要使用myStorage.StorageSource
(BindingSource)。我们也可以将这个对象引用传递给其他类(一个Form也是一个类)。
描述的操作的视觉示例:
MyStorage
数据管理器类对象:
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
public class MyStorage
{
private BindingList<StorageObject> m_Storage = null;
public MyStorage() : this(null) { }
public MyStorage(IList<StorageObject> list) {
this.m_Storage = list != null
? new BindingList<StorageObject>(list)
: new BindingList<StorageObject>();
this.StorageSource = new BindingSource(this.m_Storage, null);
}
public BindingSource StorageSource { get; }
public IList<StorageObject> Storage => m_Storage.ToList();
public StorageObject Add(string type, int amount)
{
var obj = new StorageObject(type, amount);
m_Storage.Add(obj);
return obj;
}
public bool Remove(string type, int amount)
{
if (m_Storage.Count == 0) return false;
var obj = m_Storage.FirstOrDefault(st => st.StorageType.Equals(type) && st.Amount == amount);
return Remove(obj);
}
public bool Remove(StorageObject obj)
{
if (obj != null && m_Storage.Contains(obj)) {
return m_Storage.Remove(obj);
}
else {
return false;
}
}
}
推荐阅读
- ruby-on-rails - 加载“sqlite3”Active Record 适配器时出错
- scala - 如何参数化将数据帧写入配置单元表
- google-apps-script - 当特定单元格具有特定编号时运行谷歌脚本
- azure-devops-extensions - 有没有办法在不将 doneMatch 添加到字段中的情况下合并字段?
- c# - ViewModel 列表中 DateTime 的良好做法和使用
- excel - 如何单击一个更改每次登录的href?
- windows - 使用 EnableDelayedExpansion 在 FOR 循环中计数
- docusignapi - DocuSign - 查看表单数据
- python - Yfinance - 无法获取最近的股票数据
- unity3d - unity WheelCollider 居中时移动方向错误