使用DataGridView和BindingSource.DataSource = List <t>,需要绑定到继承类型的T </t>

时间:2012-05-21 20:27:22

标签: .net winforms data-binding datagridview bindingsource

我正在寻找使用C#&amp; amp;来解决数据绑定到Winforms数据网格视图的问题。 .NET3.5。它有点涉及并包含一些我将提供代码的类。

我已经定义了一个接口:

public interface MyElement : IEditableObject {
    string Name { get; set; }
    string Description { get; set; }
}

我接下来有一个继承自MyElement的abstaract类:

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)。

在我的场景中是否有我遗漏或没有正确做的事情?我知道它与Interface&amp; amp;抽象类,但我正在使用预定义的实现,因此不能更改这些底层/基本类。提前谢谢。

  • 洛伦兹

更新 我已经尝试了一些建议并没有任何效果。所以我的问题是:我是否可以通过在MyRecordOfFields.MyMembers属性中将bindingSource1.DataSource设置为MyElementLIst来公开MyField的继承属性(比如我设计了datagridview [columns])?

这是我需要一些指导的地方:MyElement是一个界面; MyElementAdapter是一个派生自MyElement的摘要; MyElementList是MyElement的通用列表;和MyField派生自MyElementAdapter。将MyElement或任何派生类(即MyField)添加到MyElementList可以正常工作。然而,我想在UI(datagridview,controls等)中公开这些派生类的属性。

更新#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却没有。过去,底层数据的任何更新都是对底层数据和绑定源进行的 - 我想对底层数据进行更改,并将其传播到bindingsource / datagridview。

我认为以下内容会处理对datagridview的任何更改,但它不会:

    ((BindingSource)dataGridView1.DataSource).ResetBindings(false);

我是否需要使用另一种方法来更新datagridview而不添加额外的datagridview事件?

1 个答案:

答案 0 :(得分:3)

首先:

  • 请考虑接受您的问题的答案。
  • 请发布编译的代码。

真的应在界面前加 I 。它使您的代码更容易解​​释。

您正在将数据源设置为List<MyElement>。这意味着它可以绑定的可用属性是NameDescription

public interface MyElement : IEditableObject { 
    public string Name { get; set; } 
    public string Description { get; set; } 
} 

但是您手动创建DataGridView列,这些列绑定到名为MyFieldNameMyFieldDescription以及Size的属性。数据绑定器无法与您所提供的内容相匹配。

执行此操作时,无需先设置数据源:

foreach (MyElement me in myLocalFields.MyMembers) {         
            bindingSource1.Add(me);         
        }         

我相信你添加的第一个对象是建立绑定的东西,在这种情况下它是MyField,它具有你的DataGridView期望的属性。

您有几种选择。以下是其中一些没有特别的顺序。

选项1。使用AutoGenerateColumns = true,并删除所有手动创建列的代码。

选项2。创建列时,请使用MyElement属性名称:

int colIndex = dgv.Columns.Add("MyFieldName", "MyFieldName");  
dgv.Columns[colIndex].DataPropertyName = "Name";  
colIndex = dgv.Columns.Add("MyFieldDescription", "MyFieldDescription");  
dgv.Columns[colIndex].DataPropertyName = "Description";  

选项3。将对象转换为MyField,以便BindingSource为您告诉网格预期的属性生成绑定:

而不是:

bindingSource1.DataSource = myLocalFields.MyMembers;

这样做:

bindingSource1.DataSource = myLocalFields.MyMembers.Cast<MyField>();

希望你能在这里看到主题。关键是您当前正在将显式绑定列与自动创建的绑定组合在一起,并且自动绑定不是您的列设置的。我给你的选项都以不同的方式解决了这个问题。