我在WPF应用程序中有一个DataGridView
。检索整个数据是一项长期运行的任务,涉及密集的I / O.
我认为以异步方式填充网格是个好主意,即一旦元素被解码,它就会被实时添加到列表中。
在我的具体情况下,我正在从文件系统加载电子邮件,以便在与Outlook主窗口非常相似的网格上显示。
目前我已经定义了ViewModel
(此处为简化版)
public class EmailViewModel: INotifyPropertyChanged {
public string From, To, Subject, Size;
public DateTime Date;
//THIS IS A SIMPLIFIED VERSION. THE REAL CODE REALLY IMPLEMENTS INOTIFYPROPERTYCHANGED
}
然后我使用以下片段:
//Window fragment
<Window.Resources>
<CollectionViewSource x:Key="Emails" Source="{Binding}"/>
</Window.Resources>
//DataGrid fragment
<DataGrid Name="dataGridEmails" Grid.Row="1" AutoGenerateColumns="False" ItemsSource="{Binding Source={StaticResource ResourceKey=Emails}}">
<DataGrid.DataContext>
<EmailReader:EmailViewModel/>
</DataGrid.DataContext>
//Code behind
void onClick(object sender, RoutedEventArgs e){
ObservableCollection<EmailViewModel > collection = new ObservableCollection<EmailViewModel>();
DataContext = collection;
_binderThread = new Thread(o => EmailController.GetFromDirectory((string)o, collection));
_binderThread.Start(rootPath);
}
//GetFromDirectory
public static void GetFromDirectory(string directoryPath, ICollection<EmailViewModel> targetCollection)
{
string[] files = Directory.GetFiles(directoryPath, "*.eml", SearchOption.AllDirectories);
foreach (string file in files)
{
try
{
targetCollection.Add(LoadFromFile(file));
}
catch { }
}
}
由于无法从外部线程访问Window的DataContext
,因此我创建了新集合的实例,将其分配给DataContext
并传递其引用到工人线程。如果我检查调试模式,我可以看到DataContext对象被填充。
工作线程只是将新电子邮件添加到它认为是通用集合的内容中,而是添加ObservableCollection
,它应该在添加新对象时触发事件。该事件应该被UI捕获以更新DataGrid
当我运行应用程序时,我只得到一个(空的,需要在格式问题上查看更多)行。如果我尝试单击该行,我会得到一个关于集合处于非相干状态的异常(因为计数与网格不匹配)。对我来说,异常是因为DataGrid没有在每个新项目的添加上更新。
答案 0 :(得分:0)
尝试为collection.CollectionChanged
添加一个监听器:
collection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(collection_CollectionChanged);
void collection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs("collection"));
}