无法在新任务中填充数据网格
本文关键字:数据 数据网 网格 填充 新任务 | 更新日期: 2023-09-27 18:03:00
我有WPF项目与DataGrid。我使用MVVM模式。这是我VM的一部分:
class LibraryViewModel
{
#region Members
//private SimpleLibDBEntities _database;
ObservableCollection<BooksViewModel> _books = new ObservableCollection<BooksViewModel>();
int count = 0;
int sizeOfdb = 1000000;
#endregion
public ObservableCollection<BooksViewModel> Books
{
get
{
return _books;
}
set
{
_books = value;
}
}
public LibraryViewModel()
{
Task task = Task.Factory.StartNew(Generator);
}
private void Generator()
{
for (count = 0; count < sizeOfdb; count++)
{
_books.Add(new BooksViewModel { Book = new BooksSet { Id = count, Title = "Title"+count, Author = "Author", Publisher = "Publisher", Year = 1000, Note = "Note" } });
}
}
它工作,但我的DataGrid显示我只有大约50,000 - 100,000个元素(随机),而不是我的int sizeOfdb = 1000000元素。为什么会这样呢?如何修理?(没有"Task"一切正常)
在这个例子中我如何使用async/await ?类似的东西?(不工作。尝试使用dispatcher ?)
public LibraryViewModel()
{
GeneratorAsync();
}
private async void GeneratorAsync()
{
await Task.Factory.StartNew(()=>{
for (count = 0; count < sizeOfdb; count++)
{
_books.Add(...);
}
});
}
这里的基本问题是ObservableCollection
不是完全线程安全的。更具体地说,在从一个线程读取集合的同时修改来自另一个线程的集合可能是不安全的,并且ObservableCollection
会在修改集合的线程上引发CollectionChanged
事件。
我猜在这种情况下发生的是,你的后台任务创建了许多元素,并将它们添加到集合之前的UI创建和绑定发生。此时,集合中的元素被添加到DataGrid中。但是,当添加了下一个项目并且在线程池线程上引发CollectionChanged
事件时,DataGrid
的事件处理程序现在在线程池线程上运行,违反了它的线程亲和性。这会导致一个异常,终止你的任务(我猜-如果你在调试器下运行,在用户未处理的异常上打开break,你应该会看到这个)。
如果你期望生成集合项将是昂贵的(例如涉及数据库访问在实际版本中),你应该在后台线程中这样做,然后将它们添加到UI线程的ObservableCollection
-但是这个问题有一个很好的讨论。
你可以看到await/async在你的尝试公式中并没有真正帮助你,因为你只是试图用一个"即发即忘"的"async void"来包装一个"即发即忘"的任务。如果你想把创建操作从UI线程中移开,可以这样写:
private async void AddBooks()
{
var books = await Task.Run(() => GetBooks());
foreach (var book in books)
{
_books.Add(book);
}
}
private List<BooksViewModel> GetBooks()
{
List<BooksViewModel> books = new List<BooksViewModel>();
for (count = 0; count < sizeOfdb; count++)
{
books.Add(new BooksViewModel { Book = new BooksSet { Id = count, Title = "Title" + count, Author = "Author", Publisher = "Publisher", Year = 1000, Note = "Note" } });
}
return books;
}
在这种情况下,创建是在线程池线程上运行的,然后await将您带回UI线程。