2008-08-02 17 views
43

Angenommen, Sie so etwas wie die folgendenWinForms ComboBox-Datenbindung Gotcha

List<string> myitems = new List<string> 
{ 
    "Item 1", 
    "Item 2", 
    "Item 3" 
}; 

ComboBox box = new ComboBox(); 
box.DataSource = myitems; 

ComboBox box2 = new ComboBox(); 
box2.DataSource = myitems 

So, jetzt machen wir haben 2 Combo-Boxen zu diesem Array gebunden ist, und alles funktioniert. Wenn Sie jedoch den Wert eines Kombinationsfelds ändern, werden beide Kombinationsfelder auf das ausgewählte Kombinationsfeld geändert.

Nun weiß ich, dass Arrays immer durch Verweis übergeben werden (gelernt, wenn ich gelernt C: D), aber warum in aller Welt würden die Kombinationsfelder zusammen ändern? Ich glaube nicht, dass das Kombinationsfeld Steuerelement die Auflistung überhaupt ändert.

Als Arbeit um, nicht dies würde die funcionality erreichen, erwartet/erwünscht

ComboBox box = new ComboBox(); 
box.DataSource = myitems.ToArray(); 

Antwort

36

Das mit dem zu tun hat, wie in dem Dotnet Framework Datenbindungen aufgebaut, vor allem der BindingContext. Auf einer höheren Ebene bedeutet dies, dass, wenn Sie nicht anders angegeben haben, jedes Formular und alle Steuerelemente des Formulars dieselbe BindingContext teilen. Wenn Sie die DataSource Eigenschaft festlegen, wird die ComboBox die BindingContext verwenden, um eine ConcurrenyMangager zu erhalten, die die Liste umschließt. Die ConcurrenyManager verfolgt Dinge wie die aktuell ausgewählte Position in der Liste.

Wenn Sie die DataSource des zweiten ComboBox erhält es die gleichen BindingContext (Formen) verwendet werden, die die Datenbindungen verwendet, wie oben einen Verweis auf die gleichen ConcurrencyManager ergeben wird einzurichten.

Um eine detailliertere Erklärung zu erhalten, siehe BindingContext.

+1

Scheint wie eine Menge Aufwand, keinen Nutzen zu bieten und Datenbindung Kontrollen völlig intuitiv entgegenzuwirken. – Belmiris

19

Eine bessere Problemumgehung (abhängig von der Größe der Datenquelle) besteht darin, zwei BindingSource Objekte (neu ab 2.00) zu deklarieren, die Sammlung an diese zu binden und dann diese an die Comboboxen zu binden.

Ich füge ein komplettes Beispiel bei.

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

namespace WindowsFormsApplication2 
{ 
    public partial class Form1 : Form 
    { 
     private BindingSource source1 = new BindingSource(); 
     private BindingSource source2 = new BindingSource(); 

     public Form1() 
     { 
      InitializeComponent(); 
      Load += new EventHandler(Form1Load); 
     } 

     void Form1Load(object sender, EventArgs e) 
     { 
      List<string> myitems = new List<string> 
      { 
       "Item 1", 
       "Item 2", 
       "Item 3" 
      }; 

      ComboBox box = new ComboBox(); 
      box.Bounds = new Rectangle(10, 10, 100, 50); 
      source1.DataSource = myitems; 
      box.DataSource = source1; 

      ComboBox box2 = new ComboBox(); 
      box2.Bounds = new Rectangle(10, 80, 100, 50); 
      source2.DataSource = myitems; 
      box2.DataSource = source2; 

      Controls.Add(box); 
      Controls.Add(box2); 
     } 
    } 
} 

Wenn Sie sich noch mehr verwirren möchten, dann versuchen Sie immer, Bindungen im Konstruktor zu deklarieren. Das kann zu einigen wirklich kuriosen Bugs führen, daher binde ich immer im Load-Event.

+1

Vielen Dank, dass die Bindung im Konstruktor zu einigen wirklich merkwürdigen Bugs führt. Ich hatte ein ähnliches Problem, und ich habe meinen Code in das Load-Ereignis verschoben und die gebundenen Daten angezeigt. – bunggo

+0

Ich habe einige der seltsamsten nicht gemeldeten Fehler damit gefunden. Worst-Case-Szenario ist, dass eine Combobox sich weigert, ihren Fokus auf eine andere Kontrolle zu richten: D – Quibblesome

1

nur ein Tippfehler, aber im Code Dies könnte Sie zur Verfügung gestellt werden Sie nur das erste Kombinationsfeld verweisen, wenn die Datenquelle einstellen:

für box2 nicht gesetzt
ComboBox box = new ComboBox(); 
box.DataSource = myitems; 

ComboBox box2 = new ComboBox(); 
**box**.DataSource = myitems 

Die Datenquelle.