Entwickler-Ecke
WinForms - Binden einer List<T> an eine ComboBox
BlackMatrix - Mi 11.01.12 23:09
Titel: Binden einer List<T> an eine ComboBox
Guten Abend.
Ich meine, das Problem schon einmal ganz einfach gelöst zu haben, aber irgendwie funktioniert es im Moment nicht mehr.
Ich möchte eine Liste meiner Klasse an eine Combobox binden. Dabei möchte ich nicht den Code meiner Klasse ändern, soll heißen, ich möchte keine BindingList in meiner Klasse verwenden. Es soll eine einfache Liste bleiben.
Folgenden Code habe ich:
C#-Quelltext
1: 2:
| bindingSource1.DataSource = Counter.List; listBox1.DataSource = bindingSource1; |
Aber irgendwie funktioniert das nicht. Drücke ich nun einen Button in meiner Winform, die eine Methode des Counterobjekts aufruft und damit die List ändert, dann wird nichts angzeigt.
Was mache ich falsch?
Ralf Jansen - Do 12.01.12 21:53
| Zitat: |
| Dazu müsste die INotifyPropertyChanged-Schnittstelle von deiner Liste implementiert sein |
Etwas missverständlich du wolltest sagen
| Zitat: |
| Dazu müsste die INotifyPropertyChanged-Schnittstelle von den Elementen in deiner Liste implementiert sein |
;)
Th69 - Fr 13.01.12 10:19
Ja, genau das wollte ich schreiben ;-)
Kha - Fr 13.01.12 12:37
Th69 hat folgendes geschrieben : |
| über die BindingSource wird nur die Liste selber überwacht |
Selbst das kann doch nicht funktionieren bei Klassen wie List<>, die eben kein einziges Event besitzen, oder ;) ?
BlackMatrix - Fr 13.01.12 14:00
Kha hat folgendes geschrieben : |
Th69 hat folgendes geschrieben : | | über die BindingSource wird nur die Liste selber überwacht | Selbst das kann doch nicht funktionieren bei Klassen wie List<>, die eben kein einziges Event besitzen, oder ;) ? |
Ich meine auch, dass das nicht funktioniert. Berichtigt mich, wenn ich falsch liege, aber ich habe nun folgendes Mal an einem Beispiel ausprobiert:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| Manager manager = new Manager(); public MainForm() { InitializeComponent();
bindingSource1.DataSource = manager.Persons; comboBox1.DataSource = bindingSource1; }
private void button1_Click(object sender, EventArgs e) { manager.Set(); } |
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| class Manager { public List<Person> Persons { get; set; }
public Manager() { Persons = new List<Person>(); }
public void Set() { Persons.Add(new Person("Hans")); Persons.Add(new Person("Peter")); Persons.Add(new Person("Christina")); } } |
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| class Person : INotifyPropertyChanged { private string _name;
public string Name { get { return _name; } set { _name = value; OnPropertyChanged(new PropertyChangedEventArgs("Name")); } }
public event PropertyChangedEventHandler PropertyChanged;
public Person(string name) { Name = name; }
private void OnPropertyChanged(PropertyChangedEventArgs propertyChangedEventArgs) { PropertyChangedEventHandler propertyChanged = PropertyChanged; if (propertyChanged != null) propertyChanged(this, propertyChangedEventArgs); }
} |
Beim Klicken auf den Button in der MainForm habe ich in der ComboBox keine Inhalte stehen.
Ralf Jansen - Fr 13.01.12 14:48
| Zitat: |
| Ich meine auch, dass das nicht funktioniert. |
Das ist korrekt. Da die Liste nicht meldet das sie geändert wurde bekommt das die BindingSource nicht mit. Das müßtest du dann per BindingSource.ResetBindings nachholen bzw. würde ich grundsätzlich das Binding erst vornehmen wenn ich auch Daten von meiner Datenschicht bekomme also nach der Set Methode und nicht im Constructor. Das sollte üblicherweise schon reichen. Ein Datenschicht(ich bezeichne deine Managerklasse mal so) die die Daten nochmal ändert nachdem sie die an irgendeinen Nutzer geliefert hat empfinde ich doch als eher unüblich.
Oder eben gleich besser zu einer intelligenteren Listen Klasse(wie z.B. BindingList) greifen.
mats74 - Fr 13.01.12 15:35
Hallo zusammen
Ich habe den Code auch ausprobiert und der Tip mit der BindingList funktioniert einwandfrei.
Ich habe den Code folgendermassen angepasst:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53:
| private void button1_Click(object sender, EventArgs e) { Manager manager = new Manager(); manager.Set(); bindingSource1.DataSource = manager.Persons; foreach(Person person in manager.Persons) { comboBox1.Items.Add(person.Name.ToString()); } } class Manager { public BindingList<Person> Persons { get; set; } public Manager() { Persons = new BindingList<Person>(); } public void Set() { Persons.Add(new Person("Hans")); Persons.Add(new Person("Peter")); Persons.Add(new Person("Christina")); } } class Person : INotifyPropertyChanged { private string _name; public string Name { get { return _name; } set { _name = value; OnPropertyChanged(new PropertyChangedEventArgs("Name")); } } public event PropertyChangedEventHandler PropertyChanged; public Person(string name) { Name = name; } private void OnPropertyChanged(PropertyChangedEventArgs propertyChangedEventArgs) { PropertyChangedEventHandler propertyChanged = PropertyChanged; if (propertyChanged != null) propertyChanged(this, propertyChangedEventArgs); } } |
Ralf Jansen - Fr 13.01.12 15:51
| Zitat: |
| Ich habe den Code auch ausprobiert und der Tip mit der BindingList funktioniert einwandfrei. |
Bei dir hat das ganze nur nichts mit der BindingList zu tun :) Da du im Click Event gar kein Databinding verwendest sondern in die Combobox kopierst.
Wenn sich jetzt im Hintergrund nochmal die Liste ändert(darum geht es scheinbar BlackMatrix) wird die Combobox das nicht automatisch mitbekommen. Bei Databinding mit BindingList schon.
mats74 - Fr 13.01.12 15:57
... Ups :P voll ins Schwarze.
Naja, der olympische Gedanke zählt: Dabeisein ist alles :wink: .
BlackMatrix - Fr 13.01.12 16:32
Ralf Jansen hat folgendes geschrieben : |
| Zitat: | | Ich habe den Code auch ausprobiert und der Tip mit der BindingList funktioniert einwandfrei. | Wenn sich jetzt im Hintergrund nochmal die Liste ändert(darum geht es scheinbar BlackMatrix) wird die Combobox das nicht automatisch mitbekommen. Bei Databinding mit BindingList schon. |
Genau :)
Eigentlich wollte ich meine Klasse Manager, also meine Datenschicht, als gegeben ansehen. Daher will ich eigentlich auch keine BindingList anstatt einer List implementieren. Der Nächste verwendet meine Klasse und möchte gar nicht, dass die Personen an irgendein Element im UI gebunden sind und trotzdem ist die Liste eine BindingList.
Nun hatte ich mir von so einer Bindung erhofft, dass ich sie einmal im Konstruktor definiere und egal welchen Button ich in meiner Form klicke, meine Combobox immer genau die Personen widerspiegelt, die sich in der Liste befinden. Jeder Button ruft eine Methode meines Managerobjekts auf und bei jeder Methode kann es passieren, dass die List<Person> sich ändert. Wie realisiert man denn sowas?
Klar, ich könnte jetzt alle Clickereignisse der Buttons auf eine Ereignisbehandlungsroutine legen, aber irgendwie widerstrebt mir das, weil ich ja im Grunde genommen nur jeweils die Werte in der Liste angezeigt bekommen möchte, also nur einen UI Verweis von Daten an mein UI. Und dieser Verweis stellt meiner Meinung nach die Datenbindung dar, wo ich nicht jedes Mal sagen muss, jetzt aktualisiere das UI, weil es sein könnte, dass sich die Daten geändert haben.
Ralf Jansen - Fr 13.01.12 16:50
| Zitat: |
| bei jeder Methode kann es passieren, dass die List<Person> sich ändert. Wie realisiert man denn sowas? |
In dem man einen Listentyp benutzt der Bescheid sagt wenn sie sich ändert. Das tut List<T> nicht ist also eine Sackgasse. Wenn dich der Name BindingList stört(nur weil die so heißt muß man die ja nicht zum binden verwenden und wenn du die aus deiner Manager Klasse nur als IList<T> oder ähnliches veröffentlichst wird ja auch keiner drauf gestoßen das das eine entsprechende Liste ist und füllt sich genötigt zum binden) implementier halt eine eigene. Entscheidend ist IBindingList zu implementieren. Damit bekommst du ein ListChanged Event den du aus den Listen ändernden Methoden deiner Listenimplementierung() feuern mußt. Ich würde von Collection<T> ableiten und dort InsertItem, RemoveItem, SetItem überschreiben und denn ListChanged Event von dort feuern. Das sollte denke ich schon einen Großteil abdecken denn du brauchst.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!