0

C#と.Net3.5を使用して、Winformsデータグリッドビューへのデータバインディングを解決しようとしています。これは少し複雑で、コードを提供するいくつかのクラスが含まれています。

私はそのように定義されたインターフェースを持っています:

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() {
    }
}

次のように定義されたMyElementAdapterから派生したMyFieldという名前の継承されたクラスがあります。

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はリストタイプです。

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 [columns]を設計したように)を公開することは可能ですか?

ここで、ガイダンスが必要です。MyElementはインターフェイスです。MyElementAdapterは、MyElementから派生した抽象です。MyElementListは、MyElementの汎用リストです。MyFieldはMyElementAdapterから派生しています。MyElementまたは任意の派生クラス(つまりMyField)をMyElementListに追加すると機能します。それでも、UIで公開したいのはこれらの派生クラスのプロパティ(datagridview、controlsなど)です。

UPDATE#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を更新するために使用する必要がある別の方法はありますか?

4

1 に答える 1

3

まず:

  • あなたの質問に対する答えを受け入れることを検討してください。
  • コンパイルするコードを投稿してください。

インターフェイスの前にIを付ける必要があります。コードの解釈が容易になります。

データソースをに設定していますList<MyElement>。つまり、バインドできる使用可能なプロパティはとNameですDescription

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

ただしMyFieldName、andMyFieldDescriptionおよび。というプロパティにバインドされたDataGridView列を手動で作成しています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>();

うまくいけば、ここでテーマを見ることができます。重要なのは、現在、明示的にバインドされた列を自動的に作成されたバインディングと組み合わせており、自動バインディングは列の設定対象ではないということです。私があなたに与えたオプションはすべて、さまざまな方法でこの問題に対処します。

于 2012-05-21T21:31:26.323 に答える