使用带有BindingSource.DataSource =列表与LT的DataGridView;吨>中需要绑定到继承类型T的 [英] Using DataGridView with BindingSource.DataSource=List<T>, need to bind to inherited type of T

查看:373
本文介绍了使用带有BindingSource.DataSource =列表与LT的DataGridView;吨>中需要绑定到继承类型T的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找使用C#&#的数据绑定到Winforms datagridview .Net3.5。这有点涉及,包含几个课程,我将提供代码。

I'm looking to resolve databinding to a Winforms datagridview using C# & .Net3.5. It's a bit involved and encompasses a few classes which I will provide code.

我已经定义了一个接口:

I have have an Interface defined as such:

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

/ p>

I next have an abstaract class that inherits from MyElement defined as such:

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的通用列表:

There is a generic list of the interface type that is defined as such - its very basic and just retains a generic list of MyElements:

public class MyElementList : List<MyElement> {
    public MyElementList() {
    }
}

是从MyElementAdapter派生的继承类,名为MyField,定义如下:

There is an inherited class named MyField which derives from MyElementAdapter defined as such:

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是列表类型:

There is a class which uses MyElementList where MyField is the List type:

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类型的对象。

And finally, there is a form that I am using to edit an object of type 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,但没有显示添加到列表中的行数。

When this form is loaded, everything compiles and runs however when the form is displayed, the datagridview has 3 row but all blank. I am trying to directly set the datagridview's datasource to the MyElementList in the MyRecordOfFields class however nothing is displayed expect for the number of rows added to the list.

当我不将datagridview的数据源设置为列表,但是在循环中添加该列表中的每个元素,数据将按原样显示。

When I don't set the datagridview's datasource to the list, but add each element in that list in a loop, data is displayed as it should.

以下行:

        bindingSource1.DataSource = myLocalFields.MyMembers;

更改为循环:

        foreach (MyElement me in myLocalFields.MyMembers) {
            // No casting needed due to inheritance
            bindingSource1.Add(me);
        }

在我更改为循环后,我不得不添加事件处理程序来添加,删除和更新到myLocalFields(MyRecordOfFields.MyMembers)的底层数据源。

And after I changed to a loop, I had to add event handlers for adding, deleting, and updating to the underlying data source which is myLocalFields (MyRecordOfFields.MyMembers).

在我的场景中有没有丢失或不正确的东西?我知道这与Interface&抽象类,但是我正在从预定义的实现中工作,因此改变这些底层/基类不是一个选择。谢谢你提前。

Is there something I am missing or not doing correctly in my scenario?? I know it's a bit involved with the Interface & abstract classes, but I'm working from predefined implementations and so changing these underlying/basic classes is not an option. Thank you in advance.


  • 洛伦兹

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

UPDATE: I've tried a few suggestion and to no avail nothing. So my question is this: Is it possible for me to expose the inherited properties (like I designed the datagridview [columns]) of MyField by setting the bindingSource1.DataSource to the MyElementLIst in MyRecordOfFields.MyMembers property??

这是我需要指导的地方:MyElement是一个界面; MyElementAdapter是从MyElement派生的抽象; MyElementList是MyElement的通用列表; MyField来自MyElementAdapter。将MyElement或任何派生类(即MyField)添加到MyElementList中。然而,这些派生类的属性我想在UI中公开(datagridview,控件等)。

This is where I need some guidance: MyElement is an interface; MyElementAdapter is an abstract derived from MyElement; MyElementList is a generic list of MyElement; and MyField is derived from MyElementAdapter. Adding MyElement or any derived class (ie MyField) to MyElementList works. Yet it is these derived classes' properties I want to expose in the UI (datagridview, controls, etc.).

更新#2:
现在我的datagridview被限制到MyElementList,一切正常。我现在正在加入/删除/更新myLocalFields.MyMembers列表。我添加了一个带有以下代码的按钮:

UPDATE#2: Now that I have my datagridview bounded to my MyElementList everything is working fine. I am now working on adding/deleting/updating myLocalFields.MyMembers list. I've added a button with the following code:

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进行的 - 我想对底层数据进行更改,并将其传递给bindingsource / datagridview。

When this method is done, I see that my underlying data (myLocalField.MyMembers) changes, but bindingSource1 and dataGridView1 do not. In the past, any updates to the underlying data was done to the underlying data as well as the bindingsource - I would like to make changes to the underlying data and have that propogate to the bindingsource/datagridview.

我认为以下内容将会对datagridview进行任何更改,但不会:

I figured the following would take care of any changes to the datagridview but it doesn not:

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

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

Is there another method that I need to use in order for me to update the datagridview without adding additional datagridview events?

推荐答案

首先:


  • 请考虑接受您的问题的答案。

  • 请发布编辑的代码。

真的应该在我的前缀在你的界面。它使您的代码更容易解​​读。

You really should prefix your interfaces with I. It makes your code easier to interpret.

您正在将数据源设置为列表< MyElement> 。这意味着可以绑定的可用属性是名称描述

You are setting your datasource to a List<MyElement>. That means the available properties it can bind to are Name and Description.

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

但是您手动创建DataGridView列, code> MyFieldName 和 MyFieldDescription 大小。数据绑定器无法与您所提供的信息相符。

But you're manually creating DataGridView columns which are bound to properties called MyFieldName and MyFieldDescription and Size. The data binder can't match up what you told it to expect with what you gave it.

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

When you do this, without first setting the datasource:

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

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

I believe the first object you add is what establishes the bindings, and in this case it's a MyField, which has the properties your DataGridView expects.

您有几个选项。这里有一些没有特定的顺序。

You have several options. Here are some of them in no particular order.

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

Option 1. Use AutoGenerateColumns = true, and delete all the code that creates columns manually.

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

Option 2. When you create the columns, use the MyElement property names:

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生成您告诉网格期望的属性的绑定:

Option 3. Cast the objects to MyField, so that the BindingSource generates the bindings for the properties you told the grid to expect:

而不是这样:

bindingSource1.DataSource = myLocalFields.MyMembers;

执行此操作:

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

希望你可以在这里看到主题。关键是您正在将明确绑定的列与自动创建的绑定进行组合,自动绑定不是您的列的设置。我给你的选项都以不同的方式解决这个问题。

Hopefully you can see the theme here. The point is that you're currently combining explicitly bound columns with automatically created bindings, and the automatic bindings aren't what your columns are set up for. The options I've given you all address this problem in different ways.

这篇关于使用带有BindingSource.DataSource =列表与LT的DataGridView;吨&gt;中需要绑定到继承类型T的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆