2013-03-09 3 views
0

У меня есть проект WPF с DataGrid. Я использую шаблон MVVM. Это часть моей виртуальной машины: Не удается заполнить datagrid в новой задаче

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 элемента. Почему это так работает? Как отремонтировать его? (Без «задачи» все работает нормально)

И как я могу использовать async/await в этом примере? Что-то в этом роде? (Не работает. Попробуйте использовать Dispathcher?)

public LibraryViewModel() 
{ 
    GeneratorAsync(); 
} 
private async void GeneratorAsync() 
{ 
     await Task.Factory.StartNew(()=>{ 
      for (count = 0; count < sizeOfdb; count++) 
      { 
       _books.Add(...); 
      } 
     }); 
    } 
+1

Вы действительно не должны отображать 50 000 элементов в пользовательском интерфейсе, не говоря уже о 1 000 000. – svick

ответ

4

Основная проблема здесь состоит в том, что ObservableCollection не полностью потокобезопасны. Чтобы быть более конкретным, изменение коллекции из одного потока при чтении из другого может быть небезопасным, и ObservableCollection вызывает событие CollectionChanged в потоке, который изменяет коллекцию.

В этом примере я предполагаю, что ваша фоновая задача создает несколько элементов и добавляет их в коллекцию до создания пользовательского интерфейса и происходит привязка. В этот момент элементы в коллекции добавляются в DataGrid. Но когда добавляется следующий добавленный элемент и событие CollectionChanged в потоке пула потоков, обработчик событий DataGrid теперь работает в потоке пула потоков, нарушая его сродство к потоку. Это вызывает исключение, которое завершает вашу задачу (я предполагаю - вы должны это увидеть, если вы запускаете под отладчиком с отключением пользовательских необработанных исключений).

Если вы ожидаете, что генерация элементов коллекции будет дорогостоящей (например, включить доступ к базе данных в реальной версии), вы должны сделать это в фоновом потоке, а затем добавить их в в потоке пользовательского интерфейса - но this question has a good discussion of this.

Вы можете видеть, что ожидание/асинк не помогает вам в вашей попытке создания, так как вы просто пытаетесь завернуть задачу «огонь и забыть» с помощью «асинхронной пустоты». Если вы пытаетесь просто переместить создание от потока пользовательского интерфейса, как об этом:

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 получает вас обратно в поток пользовательского интерфейса.

Смежные вопросы