Ich habe alle verwandten Artikel hier in der Tafel gelesen, aber ich kann immer noch nicht mein Problem lösen, das ich beim Binden einer ObservableCollection an eine ListView habe.Änderungen in ObservableCollection aktualisieren nicht ListView
Ich habe eine CLogEntry-Modellklasse, die im Grunde eine Zeichenfolge umschließt.
/// Model of LogEntry
public class CLogEntry:INotifyPropertyChanged
{
/// Fields
private string _logEntry;
/// Property
public string LogEntry
{
get { return _logEntry; }
set
{
_logEntry = value;
RaisePropertyChanged("LogEntry");
}
}
/// PropertyChanged event handler
public event PropertyChangedEventHandler PropertyChanged;
/// Constructor
public CLogEntry(string logEntry)
{
this.LogEntry = logEntry;
}
/// Property changed Notification
public void RaisePropertyChanged(string propertyName)
{
// take a copy to prevent thread issues
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
In meinem Viewmodel habe ich eine ObservableCollection, die für sie meine CLogEntry Objekte sowie die entsprechenden öffentlichen Eigentum hält.
class CLoggerViewModel : INotifyPropertyChanged
{
/// Memory Appender object
private CMemoryAppender _memoryAppender;
/// ObservableCollection for LogEntries
private ObservableCollection<CLogEntry> _logEntries;
/// Property to expose ObservableCollection for UI
public ObservableCollection<CLogEntry> LogEntries
{
get { return _logEntries; }
}
/// Event for PropertyChanged Notification
public event PropertyChangedEventHandler PropertyChanged;
/// Constructor of viewModel
public CLoggerViewModel()
{
this._logEntries = new ObservableCollection<CLogEntry>();
this._memoryAppender = new CMemoryAppender();
this._memoryAppender.PropertyChanged += new PropertyChangedEventHandler(OnMemoryAppenderPropertyChanged);
this._memoryAppender.LogContentChanged += new LoggingEventHandler(OnLogContentChanged);
}
/// Update collection
public void OnLogContentChanged(object sender, LoggingEventArgs e)
{
/// Here i add LogEntries event based to my collection.
/// For simplicity i just used a temporarly string here.
string[] tmpString = { "A", "B", "C", "D" };
foreach (string s in tmpString)
{
this.LogEntries.Add(new CLogEntry(s));
}
}
/// Any of the properties of the MemoryAppender objects has changed
private void OnMemoryAppenderPropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.RaisePropertyChanged(e.PropertyName);
}
/// PropertyChanged EventHandler
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Mein XAML-Code für das Listview ist die folgende:
<ListView x:Name="lstLogs" DataContext ="{Binding LoggerViewModel}" ItemsSource="{Binding LogEntries}" Margin="5,5,5,5" Grid.Column="1" Grid.Row="0">
<ListView.View>
<GridView x:Name="grdLogs">
<GridViewColumn Header="Log Entry" DisplayMemberBinding="{Binding Path=LogEntries}"/>
</GridView>
</ListView.View>
</ListView>
Mein Problem ist, dass die Liste keine Daten zeigen. Aber wenn ich den Code debuggen sehe ich, dass meine Eigenschaft für die ObservableCollection aufgerufen wird und dass meine Sammlung alle LogEntries enthält, die ich hinzufüge. Also nehme ich an, dass das CollectionChanged-Ereignis ausgelöst wird und die Benutzeroberfläche meine LogEntries-Eigenschaft aufruft. Aber ich verstehe nicht, warum das ListView keine Daten zeigt.
Gibt es ein Problem mit meinem XAML-Code oder ist es ein Problem in Model und/oder ViewModel?
EDIT:
Schließlich war das Problem ein Threading-Problem. Da die ObervableCollection vom UI-Thread erstellt wird, löst sie eine Ausnahme aus, wenn ein anderer Thread die Sammlung hinzufügt/bearbeitet. Um dieses Problem zu beheben, habe ich die folgende Lösung gefunden, die eine asynchrone ObservableCollection implementiert.
ein Link hat mir geholfen, es zum Laufen zu bringen: Stackoverflow Implementing Async ObservableCollection
Wie Sie die 'DataContext' eingestellt? Und wenn Sie die 'LogEntries'-Eigenschaft instanziieren? – har07
Verwenden Sie Snoop, um Ihren DataContext und Binding Ausdruck zur Laufzeit zu überprüfen – blindmeis
@blindemeis: Spoof sagt mir: DataContext - [Logger.CLoggerViewModel] {Path = LoggerViewModel}. Aber für die BindingExpression bin ich nicht sicher. Ich habe gerade Eigenschaften für Binding.XmlNamespaceManager und BindingGroup für die ListView in Spoof gefunden. Aber beide Eigenschaften enthalten keinen Wert zur Laufzeit. – ck84vi