2008-10-31 6 views
29

Ich habe WPF ListBox, die an eine ObservableCollection gebunden ist, , wenn die Sammlung ändert, aktualisieren alle Elemente ihre Position.Eine bessere Möglichkeit zum Erzwingen der Datenbindung WPF ListBox zu aktualisieren?

Die neue Position wird in der Sammlung gespeichert, die Benutzeroberfläche wird jedoch nicht aktualisiert. So habe ich die folgenden:

void scenarioItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     ToolboxListItem.UpdatePositions(); 
     lstScenario.ItemsSource = null; 
     lstScenario.ItemsSource = ToolboxListItem.ScenarioItems; 
     this.lstScenario.SelectedIndex = e.NewStartingIndex; 
    } 

Durch die Itemssource-Einstellung auf Null und es dann erneut zu binden, wird die UI aktualisiert,

aber das ist wahrscheinlich sehr schlecht Codierung: p

Verbesserungsvorschläge?

+0

Können Sie bitte genauer erklären, was Sie mit "wenn sich die Sammlung ändert, alle Artikel aktualisieren ihre Position", nur so kann ich sicher sein, dass ich Ihre Frage richtig beantworte? – Donnelle

Antwort

72

ich eine Listbox müssen eine Objekteigenschaft gebunden, die List<MyCustomType>() vom Typ ist und ich festgestellt, dass der folgende Code die Listbox aktualisiert, wenn die Liste ist aktualisiert.

void On_MyObjProperty_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
{ 
    MyListBox.Items.Refresh(); 
} 

Wenn Sie noch Fragen, mit denen, scannen Sie den VS IDE Ausgabefenster (Strg + W, O) und sehen Sie, wenn Sie irgendwelche Bindungs ​​Fehler gemeldet erkennen.

+0

Dies scheint das Problem zu lösen, also werde ich die Bug-Frage in einen anderen Beitrag verschieben. Danke! – TimothyP

+0

Danke Gishu! –

+0

Es ist über zwei Jahre her, seit jemand dies kommentiert hat ... Vielen Dank! –

4

Ich hatte gestern das selbe Problem, und es ist ein komplettes Stück Mist :) ... Ich setze meins aber nicht mehr auf null. In meinem Szenario setze ich es auf MyList.ToArray() (nach jedem Hinzufügen zu der Liste).

Ich habe mehrere gesehen "oh, Sie müssen eine ObservableList verwenden" < - komplette Mist.

Ich habe mehrere gesehen "oh, Call 'Refresh'" < - kompletter Mist.

Bitte verzeihen Sie meine upsettedness, aber ich würde auch erwarten, dass dies funktioniert :)

+0

Vertrau mir, ich kann deine Frustration verstehen, also keine Beleidigung genommen. Ich habe GetBindingExpression versucht, aber das ist in einer Null: p – TimothyP

+0

mein "GetBindingExpression" gibt keine Null zurück ... aber selbst wenn ich "UpdateTarget" anrufe tut es nichts :(... nur in diesem Fall ... es funktioniert gut für alles andere. –

0

Wenn Sie eine ObservableList von Objekten haben und Eigenschaften in diesen Objekten ändern, gilt die Benachrichtigung nicht, da sich die Auflistung nicht direkt ändert. Ich erzwinge die Benachrichtigung, nachdem ich meine Objekteigenschaften geändert habe, indem ich mit Insert() mein geändertes Objekt wieder in die Sammlung eingefügt habe, und dann RemoveAt(), um die alte Kopie zu entfernen. Es ist nicht schön, aber es funktioniert.

9

WPF, das eine Liste/Auflistung von Elementen an eine ListBox bindet, aber die Benutzeroberfläche nach Aktualisierung der Elemente nicht aktualisiert, Gelöst.

Ich bin nur dumm. Während ich viel über die Verwendung von ObservableCollection<> anstelle von List<> gelesen hatte, ignorierte ich einfach weiter diesen Vorschlag und ging anderen Vorschlägen folgen, ohne Erfolg. Kehre zu meinen Büchern zurück und lese sie noch einmal. Es ist ziemlich gut erklärt, dass ObservableCollection<> ein Muss ist, weil List<> nicht die Schnittstelle für die ListBox benötigt, um seine Anzeige zu aktualisieren, wenn die Elemente in der Sammlung ändern.

Dies ist der aktualisierte Code:

private ObservableCollection<StringWrapper> m_AppLog; 
ObservableCollection<StringWrapper> Log { get { return m_AppLog; } } 

Ziemlich einfach und erfordert nicht etwas anderes (z Refresh()).Da ObservableCollection selbst Auslösefall der Änderung kümmert, konnte ich den unnötigen Anruf entfernen:

// notify bound objects 
OnPropertyChanged("Log"); 

ObservableCollection kein Update von einem Thread unterstützen, die es nicht schaffen haben. Weil meine Liste (ein visuelles Protokoll der letzten Fehler/Infomeldungen zeigen) kann aus verschiedenen Threads aktualisiert werden, füge ich meinen Code auf diese Weise anzupassen, um die Aktualisierung zu gewährleisten, wurde mit der Liste der eigenen Dispatcher getan:

public void AddToLog(string message) { 
    if (Thread.CurrentThread != Dispatcher.Thread) { 
     // Need for invoke if called from a different thread 
     Dispatcher.Invoke(
      DispatcherPriority.Normal, (ThreadStart)delegate() { AddToLog(message); }); 
    } 
    else { 
     // add this line at the top of the log 
     m_AppLog.Insert(0, new StringWrapper(message)); 
     // ... 

Beachten Sie auch, dass ObservableCollection<>RemoveRange() im Gegensatz zu List<> nicht unterstützt. Dies ist Teil der möglichen Anpassungen, die beim Wechsel von List zu ObservableCollection erforderlich sind.

+0

Ich habe diesen Fehler auch gemacht und es hat sehr lange gedauert, bis ich die Lösung gefunden habe. +1. – JSideris

2

Dies ist altes Zeug, aber verwenden Sie eine ObservableCollection. Wenn Sie möchten, dass die Benutzeroberfläche Aktualisierungen der Eigenschaften in den Objekten der ObservableCollection anzeigt, müssen Sie INotifyPropertyChanged in der Klassenverteidigung für dieses Objekt implementieren. Erhöhen Sie dann das Ereignis "Eigenschaft geändert" im Setter jeder Eigenschaft.

Public Class Session 
Implements INotifyPropertyChanged 

Public Event PropertyChanged As PropertyChangedEventHandler _ 
    Implements INotifyPropertyChanged.PropertyChanged 

Private Sub NotifyPropertyChanged(ByVal info As String) 
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info)) 
End Sub 

Private _name As String = "No name" 
''' <summary> 
''' Name of Session 
''' </summary> 
''' <value></value> 
''' <returns></returns> 
''' <remarks></remarks> 
Public Property Name() As String 
    Get 
     Return _name 
    End Get 
    Set(ByVal value As String) 
     _name = value 
     NotifyPropertyChanged("Name") 
    End Set 
End Property 
6

Ich kann ein ähnliches Problem zu haben, was Sie haben, aber ich bin nicht sicher.

Ich hatte eine ObservableCollection<MyEntity> und eine ListBox daran gebunden. Aber für einige seltsamen Grund meine ListBox wurde nicht aktualisiert, wenn ich die Eigenschaften der MyEntity Objekte in der Liste änderte.

Nach längerem Suchen fand ich die folgende Seite und ich hatte nur damit Sie wissen:

http://www.wblum.org/listbind/net3/index.html

Es ist eine sehr gute Beschreibung dessen, was Sie ListBox zu tun haben, um zu aktualisieren, wenn sich die Liste oder die darin enthaltenen Objekte ändern. Ich hoffe, Sie werden davon profitieren.

+0

das ist sehr gut, vielen Dank! Besonders, dass Sie nur INotifyPropertyChanged für die in der 'ListBox' enthaltene Klasse implementieren müssen, war für mich interessant. –

+1

Diese Domain steht zum Verkauf. –

0

Für mich sieht es eher wie ein Fehler in ListBox und ListView. Ich bin an eine ObservableCollection gebunden, die Elemente in der Sammlung implementieren INotifyPropertyChanged. Die Benutzeroberfläche zeigt keine hinzugefügten Elemente an, wenn ich meine Schaltfläche "Element hinzufügen" dynamisch drücke, aber ich habe ein Gegensteuerelement, das an MyCollection.Count gebunden ist. Diese Zählersteuerung wird jedes Mal erhöht, wenn ich meine Schaltfläche "Objekt hinzufügen" drücke. Wenn ich die Größe der Ansicht ändere, zeigt das Listenfeld alle meine hinzugefügten Elemente an. Daher ist die ItemSource-Bindung für das ListBox-Steuerelement unterbrochen. Ich habe auch darauf geachtet, zu keinem Zeitpunkt eine neue MyCollection zu erstellen, die die Bindung aufheben würde. Boo Hoo.

+0

Lolz, in meiner Situation war das Problem, dass jemand tatsächlich eine Klasse namens ObservableCollection implementiert! Also hat meine Sammlung INotifyCollectionChanged nicht implementiert, obwohl sie ObservableCollection genannt wurde. Meine Güte. Nachdem ich den beanstandeten Namespace entfernt und System.Collections.ObjectModel verwendet hatte, war alles in Ordnung. Dah! – flobadob