【发布时间】:2014-11-02 09:54:58
【问题描述】:
我已经阅读了看板中的所有相关文章,但仍然无法解决将 ObservableCollection 绑定到 ListView 时遇到的问题。
我有一个 CLogEntry 模型类,它基本上包装了一个字符串。
/// 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));
}
}
}
在我的 ViewModel 中,我有一个 ObservableCollection,它保存着我的 CLogEntry 对象以及它的相应公共属性。
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));
}
}
}
我的 ListView 的 XAML 代码如下:
<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>
我的问题是列表没有显示任何数据。 但是当我调试代码时,我可以看到我的 ObservableCollection 属性被调用,并且我的集合包含我添加的所有 LogEntries。 所以我假设 CollectionChanged 事件被触发并且 UI 正在调用我的 LogEntries 属性。 但我不明白为什么 ListView 不显示任何数据。
我的 XAML 代码有问题还是模型和/或 ViewModel 有问题?
编辑:
最后是线程问题。 由于 ObervableCollection 是由 UI 线程创建的,因此如果另一个线程正在添加/操作集合,它会引发异常。 为了摆脱这个问题,我找到了以下实现异步 ObservableCollection 的解决方案。
以下链接帮助我使其正常工作: Stackoverflow Implementing Async ObservableCollection
【问题讨论】:
-
如何设置
DataContext?当你实例化LogEntries属性时? -
请使用 Snoop 在运行时检查您的 DataContext 和绑定表达式
-
@blindemeis:恶搞告诉我:DataContext - [Logger.CLoggerViewModel] {Path=LoggerViewModel}。但是对于 BindingExpression 我不确定。我刚刚在 Spoof 中找到 ListView 的 Binding.XmlNamespaceManager 和 BindingGroup 的属性。但是这两个属性在运行时都没有任何值。
标签: wpf listview data-binding observablecollection