Przeczytałem wszystkie powiązane artykuły tutaj na tablicy, ale nadal nie mogę rozwiązać mojego problemu, który mam podczas wiązania ObservableCollection do ListView.Zmiany w ObservableCollection nie aktualizują ListView
Mam klasę modelu CLogEntry, która zasadniczo opakowuje ciąg.
/// 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));
}
}
}
W moim ViewModel Mam ObservableCollection, która posiada swoje obiekty CLogEntry jak również odpowiednią własność publiczną dla niego.
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));
}
}
}
Mój kod XAML dla ListView jest następujący:
<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>
Moim problemem jest to, że lista nie pokazuje żadnych danych. Ale kiedy debuguję kod, widzę, że moja właściwość dla ObservableCollection zostaje wywołana i że moja kolekcja zawiera wszystkie dodane przeze mnie LogEntries. Zakładam więc, że zdarzenie CollectionChanged zostanie wyrzucone, a interfejs wywoła moją właściwość LogEntries. Ale nie rozumiem, dlaczego ListView nie wyświetla żadnych danych.
Czy występuje problem z moim kodem XAML lub czy jest to problem w modelu i/lub ViewModel?
EDIT:
Wreszcie problemem była kwestia gwintowania. Ponieważ klasa ObervableCollection jest tworzona przez wątek interfejsu użytkownika, generuje wyjątek, jeśli inny wątek dodaje/manipuluje kolekcją. Aby pozbyć się tego problemu, znalazłem następujące rozwiązanie, które implementuje Asynchronous ObservableCollection.
poniższych linków pomógł mi dostać pracy: Stackoverflow Implementing Async ObservableCollection
Jak ustawić 'DataContext'? A kiedy tworzysz instancję 'LogEntries'? – har07
pls użyć Snoop, aby sprawdzić DataContext i Binding Expression w czasie wykonywania – blindmeis
@ blindemeis: Fałszywy mi mówi: DataContext - [Logger.CLoggerViewModel] {Path = LoggerViewModel}. Ale dla BindingExpression nie jestem pewien. Właśnie znalazłem Właściwości dla Binding.XmlNamespaceManager i BindingGroup dla ListView w Spoof. Ale obie właściwości nie trzymają żadnej wartości podczas wykonywania. – ck84vi