Ho letto tutti gli articoli correlati qui nella scheda ma non riesco ancora a risolvere il mio problema che ho quando leghiamo una ObservableCollection a un ListView.Le modifiche in ObservableCollection non aggiornano ListView
Ho una classe di modello CLogEntry che fondamentalmente avvolge una stringa.
/// 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));
}
}
}
Nel mio ViewModel Ho un ObservableCollection che contiene i miei oggetti CLogEntry nonché la corrispondente proprietà pubblica per esso.
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));
}
}
}
Il mio codice XAML per il controllo ListView è la seguente:
<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>
il mio problema è che l'elenco non mostra alcun dato. Ma quando eseguo il debug del codice, posso vedere che la mia proprietà per ObservableCollection viene chiamata e che la mia raccolta contiene tutti i LogEntries che aggiungo. Quindi presumo che l'evento CollectionChanged venga generato e che l'interfaccia utente stia chiamando la mia proprietà LogEntries. Ma non capisco perché ListView non mostri alcun dato.
C'è un problema con il mio codice XAML o è un problema nel modello e/o nel ViewModel?
EDIT:
Infine, il problema è stato un problema di threading. Poiché ObervableCollection viene creato dal thread dell'interfaccia utente, genera un'eccezione se un altro thread sta aggiungendo/manipolando la raccolta. Per risolvere questo problema, ho trovato la seguente soluzione che implementa una ObservableCollection asincrona.
seguenti link mi ha aiutato a farlo funzionare: Stackoverflow Implementing Async ObservableCollection
Come si imposta il 'DataContext'? E quando istanziate la proprietà 'LogEntries'? – har07
pls usa Snoop per controllare DataContext e Binding Expression in fase di esecuzione – blindmeis
@blindemeis: Spoof mi sta dicendo: DataContext - [Logger.CLoggerViewModel] {Path = LoggerViewModel}. Ma per BindingExpression non sono sicuro. Ho appena trovato le proprietà per Binding.XmlNamespaceManager e BindingGroup per ListView in Spoof. Ma entrambe le proprietà non contengono alcun valore durante il runtime. – ck84vi