1

最初に、通常のバインディング (テキスト ボックスの Text などの標準プロパティを使用) について少しお話ししたいと思います。ここでのサンプル グリッドには 2 行しかありません (簡単にするため)。2 つの列 (ID と名前)、DataGridView (myGrid)、および TextBox (myTextBox) を持つ 2 つの行 (myDataTable) のテーブルがあるとします。データをバインドするコードは次のとおりです。

myGrid.DataSource = myDataTable;
myTextBox.DataBindings.Add("Text", myDataTable, "Name");

データをバインドした後、グリッドで選択が変更されると、情報はコントロール TextBox に自動的に更新されます。たとえば、2 つの行は次のとおりです。

ID       |       Name
1                .NET
2                Java

最初、グリッド内の選択はインデックス 0 で、myTextBox のテキストは「.NET」で、選択を次の位置 (インデックス 1) に移動します。myTextBox のテキストは「Java」で、何度も何度も移動し、前後に移動します。私が期待するように、それは正常に動作します。しかし、List というカスタム プロパティを持つコントロールができました。これは List のタイプであり、読み取り専用です。それをテーブルの列 (Name など) にバインドしたいのですが、同じバインド ルールを実行しますが、カスタム プロパティの型が私の Name 列が文字列のタイプである間にリストします。バインディングコードは次のとおりです。

Binding bind = new Binding("List", myDataTable, "Name"){
   ControlUpdateMode = ControlUpdateMode.Never //Because my List property is readonly
};
//formating string data before updating to the datasource
bind.Parse += (s,e) => {
  List<string> data = (List<string>) e.Value;
  if(data.Count == 0) e.Value = DBNull.Value;
  else e.Value = string.Join(",",data.ToArray());//format as comma separated string
};
myCustomControl.DataBindings.Add(bind);

この場合、myDataTable には現在、次のように列 Name にデータがないとします。

ID      |      Name
1           <DBNull.Value>   <--- current index
2           <DBNull.Value>

デモを実行した後、グリッドの現在の選択インデックスは 0 です。たとえば、次のように更新して、myCustomControl プロパティ リスト (参照ではなくアイテム) の値を変更してみます。

myCustomControl.List.Add(".NET");
myCustomControl.List.Add("Java");

次に、グリッド内の選択を次の位置 (インデックス 1) に移動すると、次のように、値 ".NET,Java" が列 Name の行 0 のデータソースに更新されます。

ID      |      Name
1             .NET,Java
2                             <----- current index

選択をインデックス 0 に戻すと、行 1 の列 Name の値も次のように「.NET,Java」に更新されます。

ID      |      Name
1             .NET,Java     <----- current index
2             .NET,Java

これは私が望むものではありません。つまり、コントロール myCustomControl を介して値を更新する必要があります。ここに私が欲しいものがあります:

ID      |      Name
1             .NET,Java     <----- current index
2             

インデックス 1 からインデックス 0 に戻る時点で、List プロパティの値はまだ 2 つの項目 (「.NET」と「Java」) を持つリストであるため、移動後にこれが更新されることがわかります。行 1 の列 Name のセル。行 0 の列 Name のセルに更新された後、List プロパティの値をリセットして、選択範囲がインデックス 1 のときに既に空になるようにする方法を見つけています。Parse イベント ハンドラーを次のように変更しようとしましたが、良い揺れはありません。

bind.Parse += (s,e) => {
  List<string> data = (List<string>) e.Value;
  if(data.Count == 0) e.Value = DBNull.Value;
  else e.Value = string.Join(",",data.ToArray());//format as comma separated string
  //I think at here, the value has been already updated to the datasource
  //and I can perform the reset
  myCustomControl.List.Clear();
};

ただし、値がデータソースに更新される前にクリアされるように見えるため、データソースに更新される値はありません (「.NET、Java」ではなく、DBNull.Value です)。

次に、これも試しました:

bind.BindingComplete += (s,e) => {
   if(e.BindingCompleteContext == BindingCompleteContext.DataSourceUpdate)
      myCustomControl.List.Clear();
};

データがデータソースに更新されているかどうかを確認する必要があると思いました。リストをクリアできます。また、クリアする前に true としてマークし、クリア後に false にリセットするフラグをいくつか試しました。このフラグを使用して bind.Parse の流れを制御しますが、何もしませんでした。

この問題を解決するアイデアはありますか? あなたの助けは非常に高く評価されます! ありがとうございました。

4

1 に答える 1

1

私は自分で解決策を見つけました。実際、とにかくリストをリセットすることはできません。これにより、グリッド内の行を切り替えるときに、基になるデータソースが更新されます。ここでの重要なアイデアは、最初に DataSourceUpdateMode を DataSourceUpdateMode.Never に設定し、リストが変更されようとしているときはいつでも、DataSourceUpdateMode を DataSourceUpdateMode.OnPropertyChanged に変更することです。Parse イベント ハンドラーで、解析が完了したら、DataSourceUpdateMode を DataSourceUpdateMode.Never にリセットします。そして、それは非常にうまくいきます。基になるデータソースは、ユーザーが入力または選択してコントロールの値 (リスト) を変更した場合にのみ更新されます...

すべてのコードは次のとおりです。

Binding bind = new Binding("List", myDataTable, "Name"){
  ControlUpdateMode = ControlUpdateMode.Never, //Because my List property is readonly
  DataSourceUpdateMode = DataSourceUpdateMode.Never//This will be turned on when preparing to change the List's value
};
//formating string data before updating to the datasource
bind.Parse += (s,e) => {
  List<string> data = (List<string>) e.Value;
  if(data.Count == 0) e.Value = DBNull.Value;
  else e.Value = string.Join(",",data.ToArray());//format as comma separated string
  //At here reset the DataSourceUpdateMode to Never
  //We can also do this in BindingComplete event handler with BindingCompleteContext = BindingCompleteContext.DataSourceUpdate
  myCustomControl.DataBindings[0].DataSourceUpdateMode = DataSourceUpdateMode.Never;
};
myCustomControl.DataBindings.Add(bind);

myCustomControl には、UpdateList() と呼ばれる List プロパティの新しい項目を更新/入力するメソッドがあります。メソッドの最初の部分で、次のように DataSourceUpdateMode を OnPropetyChanged に設定する必要があります。

public void UpdateList(){
    if(DataBindings.Count > 0) DataBindings[0].DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
    //The remaining code for populating/updating new items goes below
    ....
}

それだけで、とてもきれいです。これが私と同じ状況に遭遇する誰かを助けることを願っています.ありがとう!

于 2013-04-29T15:24:20.303 に答える