I have been reading all the related articles here in the board but I still can't solve my problem that I have when binding an ObservableCollection to a ListView.
I have a CLogEntry model class which basically wraps a string.
/// 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 my ViewModel I have an ObservableCollection that holds my CLogEntry objects as well as the corresponding public property for it.
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));
}
}
}
My XAML code for the ListView is the following:
<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>
My Problem is that the list does not show any data. But when I debug the code I can see that my property for the ObservableCollection gets called and that my collection holds all the LogEntries that I add. So I assume that the CollectionChanged event gets fired and the UI is calling my LogEntries property. But I don't understand why the ListView does not show any data.
Is there a problem with my XAML code or is it a problem in model and/or ViewModel?
EDIT:
Finally the problem was a threading issue. Since the ObervableCollection is created by the UI thread it throws an exception if another thread is adding/manipulating the collection. To get rid of this problem i found the following solution that implements an Asynchronous ObservableCollection.
Following links helped me to get it working: Stackoverflow Implementing Async ObservableCollection