我正在寻找使用 C# 和 .Net3.5 解决与 Winforms datagridview 的数据绑定问题。它有点复杂,包含一些我将提供代码的类。
我有一个这样定义的接口:
public interface MyElement : IEditableObject {
string Name { get; set; }
string Description { get; set; }
}
接下来我有一个从 MyElement 继承的抽象类,定义如下:
abstract public class MyElementAdapter : MyElement {
private string myName;
private string myDescription;
private ModelElement myParent;
public MyElementAdapter(MyElement parent) {
myName = "New_Element";
myDescription = string.Empty;
}
virtual public string Name {
get { return myName; }
set { myName = value; }
}
virtual public string Description {
get { return myDescription; }
set { myDescription = value; }
}
public MyElement Parent {
get { return myParent; }
set { myParent = value; }
}
public void BeginEdit() {
// code to begin edit
}
public void CancelEdit() {
// code to cancel edit
}
public void EndEdit() {
// code to end edit
}
}
有一个这样定义的接口类型的通用列表 - 它非常基本,只保留了 MyElements 的通用列表:
public class MyElementList : List<MyElement> {
public MyElementList() {
}
}
有一个名为 MyField 的继承类,它派生自 MyElementAdapter,定义如下:
public class MyField : MyElementAdapter {
private int size;
public MyField(MyElement parent) : base(parent) {
size = 1;
}
public string MyFieldName {
get { return this.Name; }
set { this.Name = value;}
}
public string MyFieldDescription {
get { return this.Description; }
set { this.Description = value;}
}
public int Size {
get { return size; }
set { size = value; }
}
}
有一个使用 MyElementList 的类,其中 MyField 是 List 类型:
public class MyRecordOfFields : MyElementAdapter {
private MyElementList myMembers;
public MyRecordOfFields(MyElement parent) : base(parent) {
myMembers = new MyElementList();
}
public MyElementList MyMembers {
get { return myMembers; }
set { myMembers = value; }
}
}
最后,我使用了一个表单来编辑 MyRecordOfFields 类型的对象。
public class Form1 : Form {
private BindingSource bindingSource1;
private MyRecordOfFields myLocalFields;
private DataGridView dgv;
private Form1_Load() {
myLocalFields = new MyRecordOfFields(null);
MyField field1 = new MyField(null);
field1.MyFieldName = "Field_1";
field1.MyFieldDescription = "Description1";
field1.Size = 3;
myLocalFields.MyMembers.Add(field1);
MyField field2 = new MyField(null);
field2.MyFieldName = "Field_2";
field2.MyFieldDescription = "Description2";
field2.Size = 3;
myLocalFields.MyMembers.Add(field2);
MyField field3 = new MyField(null);
field3.MyFieldName = "Field_3";
field3.MyFieldDescription = "Description3";
field3.Size = 3;
myLocalFields.MyMembers.Add(field3);
bindingSource1 = new BindingSource();
bindingSource1.AllowNew = true;
dgv.AutoGenerateColumns = false;
int colIndex = dgv.Columns.Add("MyFieldName", "MyFieldName");
dgv.Columns[colIndex].DataPropertyName = "MyFieldName";
colIndex = dgv.Columns.Add("MyFieldDescription", "MyFieldDescription");
dgv.Columns[colIndex].DataPropertyName = "MyFieldDescription";
colIndex = dgv.Columns.Add("Size", "Size");
dgv.Columns[colIndex].DataPropertyName = "Size";
dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
dgv.AutoResizeColumns();
bindingSource1.DataSource = myLocalFields.MyMembers;
dgv.DataSource = bindingSource1;
dgv.Invalidate();
}
}
加载此表单时,所有内容都会编译并运行,但是当显示表单时,datagridview 有 3 行但全为空白。我正在尝试将 datagridview 的数据源直接设置为 MyRecordOfFields 类中的 MyElementList,但是对于添加到列表中的行数,没有显示任何内容。
当我没有将 datagridview 的数据源设置为列表,而是在循环中添加该列表中的每个元素时,数据将按应有的方式显示。
以下行:
bindingSource1.DataSource = myLocalFields.MyMembers;
改为循环:
foreach (MyElement me in myLocalFields.MyMembers) {
// No casting needed due to inheritance
bindingSource1.Add(me);
}
在我更改为循环后,我必须添加事件处理程序以添加、删除和更新底层数据源,即 myLocalFields (MyRecordOfFields.MyMembers)。
在我的场景中是否有我遗漏或没有正确执行的内容?我知道这有点涉及接口和抽象类,但我正在使用预定义的实现,因此更改这些底层/基本类不是一种选择。先感谢您。
- 洛伦兹
更新: 我尝试了一些建议,但无济于事。所以我的问题是:我是否可以通过将 bindingSource1.DataSource 设置为 MyRecordOfFields.MyMembers 属性中的 MyElementLIst 来公开 MyField 的继承属性(就像我设计的 datagridview [列])?
这是我需要一些指导的地方: MyElement 是一个接口;MyElementAdapter 是从 MyElement 派生的抽象;MyElementList 是 MyElement 的通用列表;MyField 是从 MyElementAdapter 派生的。将 MyElement 或任何派生类(即 MyField)添加到 MyElementList 是可行的。然而,我想在 UI 中公开这些派生类的属性(datagridview、控件等)。
更新#2: 现在我的 datagridview 绑定到 MyElementList 一切正常。我现在正在添加/删除/更新 myLocalFields.MyMembers 列表。我添加了一个带有以下代码的按钮:
private void AddItem_Click(object sender, EventArgs e) {
MyField field1 = new MyField(null);
field1.MyFieldName = "Field_" + myLocalFields.MyMembers.Count + 1;
field1.MyFieldDescription = "Description" + myLocalFields.MyMembers.Count + 1;
field1.Size = myLocalFields.MyMembers.Count + 1;
myLocalFields.MyMembers.Add(field1);
((BindingSource)dataGridView1.DataSource).ResetBindings(false);
}
完成此方法后,我看到我的基础数据 (myLocalField.MyMembers) 发生了变化,但 bindingSource1 和 dataGridView1 没有。过去,对底层数据的任何更新都是对底层数据和绑定源进行的——我想对底层数据进行更改并将其传播到绑定源/datagridview。
我认为以下内容会处理对 datagridview 的任何更改,但它不会:
((BindingSource)dataGridView1.DataSource).ResetBindings(false);
是否需要使用另一种方法来更新 datagridview 而无需添加额外的 datagridview 事件?