[WPF] List Binding an ListView
-
Heiho,
Ich habe in meiner Applikation eine List<Items> _items = new List<Items>();
Items selber hat entsprechende Properties zum setzen und holen.Ich geb in der ListView dem ItemSource ein Binding
Und im Load des Festers geb ich der Liste als DataContext diese _items liste.Die ListView ist über einer GridView Multicolumn designend, und die anzuzeigenden items werden an den Properties gebunden.
Nun möchte ich ein neues Item der Liste zuordnen, das mach ich mittels _items.add
Leider wird die ListView nicht entsprechend aktualisiert.
Ich muss erst DataContext leeren und neu zuweisen damit das neue item mit angezeigt wird.Daher die Frage, wie kann ich diese ListView dynamisch binden ohne es per Hand „aktualisieren“ zu müssen, die Daten liegen nur in der _items Liste vor.
Ich bin noch am lernen von WPF und meine nächste Idee wäre das ich die Daten in der XML im Speicher ableg, und die Liste an die XML binden lass, weiß aber nicht in wie fern das überhaupt funktioniert.
Das Binding selber klappt wunderbar, ich kann die Items in der Liste editieren und es ist in der _items auch geändert.
{Habe das Element über DataTemplate als TextBox angezeigt}Das nächste Problem ist wie ich einem selektiertes item in der Liste dem reellen item zuordne bei klick oder Tastendruck.
Noch geht es durch _items[_list.SelectedIndex] aber sobald ich es anders sortiert anzeigen lass als es in der Liste abgelegt ist, funktioniert das nicht mehr, ich müsste das _list.SelectedItem nach einem iterator auf dem listen Element casten, aber ob das geht und zuverlässig ist weiß ich nicht so recht /=Über ein DataSet funktioniert das aktualisieren in der Liste automatisch, nur da muss ich zu sehr mit den Colums und Rows arbeiten, das liegt nicht in mein Interesse irgendwie.
Kann mir jemand helfen?
// hier die relevanten ausschnitte aus dem code
<!--.xaml--> <ListView ... ItemSource={Binding}> ... <TextBox Test="{Binding Path=Info}"/> ... <GridViewColumn ... DisplayMemberBinding="{Binding Number}"/> </ListView> //.cs private void Add_Click(object sender, RoutedEventArgs e) { Items item = new Items(); item.Info = "Bla"; item.Number = 321; _items.add(item); UpdateList(); } private void UpdateList() { _list.DataContext = null; _list.DataContext = _items; } private List<Items> _items = new List<Items>();
wenn es zu wenig Code ist, sagt bitte bescheid dann stell ich mehr rein.
-
DataBinding beruht ja darauf dass irgendwer wem sagt das sich was ändert. Das kann eine List<T> nicht, die hat keinerlei Möglichkeiten zu sagen dass sie sich geändert hat. Dafür gibts in WPF das INotifyCollectionChanged Interface und OberservableCollection<T> implementiert dieses schon. Sprich statt List<T> ObservableCollection<T> und schon tut die automatische Aktualisierung.
Dein zweites Problem verstehe ich nicht ganz. Sobald du was makierst gibts doch das SelectionChanged Event welches in den EventArgs die makierten Elemente mitbringt. Du musst nicht anhand von Indizies dir die makierten Elemente aus der Liste raussuchen.
-
Hei das liest sich interessant was du da schreibst - werd ich mal damit rumspielen - vielen dank dafuer
das ich das element per eventargs stimmt, ich bin nur grad n bissl ueberfragt was fuer ein objekt das ist - nach was muss ich es casten
ist es direkt das objekt aus der liste als referenz ? ist es ein iterator auf dem element oder eine kopie ?
-
ich hab ein cast gefunden der keine exception wirft - nur das bringt mir nicht viel
private void _list_SelectionChanged(object sender, SelectionChangedEventsArgs e) { Object[] selectedItems = (Object[])e.AddedItems; Item firstItem = (Item)selectedItems[0]; }
fuer die anzeige reicht das - nur ich brauch die zugehörigkeit in der liste
ich moechte naemlich ein element auswaehlen - es anzeigen und dann die moeglichkeit bieten es zu aendern
nachdem es angezeigt und geaendert wird muss ich ja auch wissen wo ist das element in der ObservableCollection listedas naechste problem ist - ich moechte ein item per ENTF taste aus der liste loeschen lassen
nur
wie bekomm ich die zuordnung von der ListView zu der collection liste ?private void _list_KeyDown(object sender, KeyEventArgs e) { if(e.Key == Key.Delete && _list.SelectedIndex != -1) { // remove item from collection } }
also fuer die anzeige funktioniert alles praechtig, aber wie komm ich an das item aus der collection um selected items zu entfernen oder zu aendern, irgendwie fehlt mir da die verbindung /=
-
Erstmal zu dem Post davor.
In .Net arbeitet man immer mit Referenzen wenn es sich um Klassen handelt. Iteratoren werden in der Art wie in C++ so gut wie gar nicht verwendet. Und es gibt in .Net auch keine allgemeingültige Möglichkeit um Kopien von Objekte zu erstellen. Deshalb auf die Frage was zurückgegeben wird: immer Referenzen!
Damit kommen wir auch zu den weiteren Fragen: Du brauchst gar nicht wissen wo dein Element in der Liste steht, da du wie gesagt ne Referenz darauf hast. Wenn du was ändern willst, tu es einfach, denn du hast doch schon das Obekt aus der Liste.
Dein ersten Eventhandler hast du aber arg umstädlich
private void _list_SelectionChanged(object sender, SelectionChangedEventsArgs e) { Item firstItem = e.AddedItems[0] as Item; }
AddedItems ist doch schon eine Liste wo du direkt per indexer zugreifen kannst, musst das net in ein Array casten.
Du schreibst ja du willst da was anzeigen. Wie denn? Wenn du vorhast z.b. eine ListView und daneben von mir aus TextBoxen die die einzelnen Werte des markierten Items dann auch ändern sollen, zu machen, dann geht das über DataBinding viel einfacher. Du setzt für die ListView einfach das IsSynchronizedWithCurrentItem Property auf true und bindest deine TextBoxen (oder was auch immer du zum editieren der Werte des Items benutzen möchtest) einfach gegen deine ursprüngliche Collection. Wie durch ein Wunder (naja, net wirklich *gg*) werden dann deine TextBoxen immer gegen das aktuell markierte Item gebunden. Wenn du nun beim Binding noch das passende Property angibst zeigt jedes deiner TextBoxen immer ein Property zum editieren an.
DataBinding in WPF ist wirklich was feines wenn man die Kniffe raus hat, aber dazu gibts genug Beispiele in der MSDN Library, auch genau zu dem Vorgehen was ich grad geschildert hab. Da solltest dir auch mal die CollectionView Klasse anschaun, durch die wird nämlich obriges Vorgehen erst möglich und gerade was Sortierung usw. angeht welches du ja auch haben willst, ist das Wissen um diese Klasse recht hilfreich.
Und nun noch kurz zum Löschen, da spielt genau das rein was ich oben gesagt hab zu den Referenzen. Du bekommst als selektiertes Item genau das Ding aus deiner Liste, also kannst du einfach DeineListe.Remove(deinSelektiertesItem); aufrufen, und schon wird das Item aus der Liste entfernt.
-
ich hab das jetzt so geloest
beim loeschen hol ich das Item welches selektiert ist aus der ListView und geb der _items list per remove dieses item, dadurch funktioniert das praechtig
bzgl des aenderns hab ich das so gemacht
wenn ein item angeklickt wird, wird es geholt wie es oben zu sehen ist, dann in den entsprechenden textboxen angezeigt
sobald der user dann auf "change" klickt, wird das selektierte item aus der listview geholt
dann die position per _items.IndexOf geholt - an der stelle dann das neue eingefuegt und das alte per remove entferntzuerst hatte ich das neue item direkt an dem item in den entsprechenden index zugewiesen - nur dann spinnt die listview rum - das item sieht dann immer aus als waere es selektiert und ich kann es nicht mehr auswaehlen, o ich multiselekt oder single select hab spielte dabei keine rolle
darum tausch ich das item direkt ausich werds wahrscheinlich so machen das ich ne eigene collection klasse mach welches schon eine "replace" beinhalten wird
-
Ich weiß net ob du meine Antwort schon gelesen hattest, aber das mit dem ersetzen des Items in der Liste ist völlig unnötig. Selbst wenn man es net per DataBinding löst wie ich vorgschlagen hab reicht doch sowas vollkommen aus[Pseudocode]:
// aktuell makiertes Item holen Item myItem = ListView.SelectedItem; // neue Werte zuweisen myItem.MeinProperty1 = textBox1.Text; myItem.MeinProperty2 = textBox2.Text; // fertig
Da myItem ja ne Referenz ist wirken sich die Änderungen doch in der Liste aus. Wenn die evtl. nur net angeeigt werden, liegt das daran das die Item Klasse das nicht unterstützt, die muss nämlich INotifyPropertyChanged implementieren.
-
hi talla, ich hatte deinen post tatsaechlich gar nicht gesehen #gg
ich werd mal damit rumspielen und mich auch ueber dieses IsSync .. belesen - genauso zu der collectionview
vielen dank dafuer {=
//dazuedit
ich hab nu mit dem Sync gespielt und die binding entsprechend gesetzt - tada - den "change" button kann ich nu wegwerfen - das binding funktioniert direkt wenn ich ein item selektiere oder in der textbox was aender in beide richtungen - sehr geil {=vielen dank {=
-
// alles wegedit, hatte was falsch gemacht
hehe nun hab ich was gutes hinbekommen
eine SortedList in einer eigenen collection welches INotifyCollectionChanged implementiert
in der listview die moeglichkeit einer sortierung per header klick mit einer default sortierung der elemente {=
und dazu noch ein binding zu den textboxen in beide richtungen {=