#c_sharp #многопоточность #mvvm #backgroundworker
Пишу программу на C# с mvvm. У меня есть два эквивалентных куска кода, в которых,по-моему мнению, должна происходить абсолютно одинаковая работа. Суть в чем- постепенная подгрузка(добавление) элементов в коллекцию с помощью BackgroundWorker. Коллекция имеет биндинг с listview и соответственно постепенное(пообъектное) добавление в коллекцию отображается в этом listview. Код: public class ListContactViewModel : ViewModelBase { public ObservableCollectionDialogListFirstPage { get;set;} Dispatcher _dispatcher; public ListContactViewModel(VkApi vk) { _dispatcher = Application.Current.Dispatcher; DialogListFirstPage = new ObservableCollection (); var bw1 = new BackgroundWorker(); bw1.DoWork += (o, e) => { FirstDialogPageMethod(vk); //Создание коллекции диалогов }; bw1.RunWorkerAsync(); //внимания в этом методе достойна только строчка добавления в коллекцию private void FirstDialogPageMethod(VkApi vk) { int totalCount, unreadCount; var GetFirstDialigPage = vk.Messages.GetDialogs(20, 0, out totalCount, out unreadCount); foreach (var i in GetFirstDialigPage) { var Names = vk.Users.Get(i.UserId.ToString(), ProfileFields.FirstName); _dispatcher.Invoke(()=> DialogListFirstPage.Add(new MessageChild() { AuthorFirstName = Names.FirstName, AuthorLastName = Names.LastName, Body = i.Body, UserId = i.UserId, Date = i.Date, ChatActiveIds = i.ChatActiveIds, Title = i.Title, UsersCount = i.UsersCount, ChatId = i.ChatId })); } } на всякий случай приведу строчку биндинга из xaml: И все закономерно: окно открывается пустым и я наблюдаю постоянное добавление элементов в список. Ситуация 2: Из предыдущего окна я перехожу в следующее , в котором аналогичная ситуация public class CurrentDialogViewModel:ViewModelBase { public ObservableCollection ReadyCollection { get; set; } Dispatcher disp; public CurrentDialogViewModel(VkApi vk,MessageChild parametr) { disp = Application.Current.Dispatcher; ReadyCollection = new ObservableCollection (); var bw2 = new BackgroundWorker(); bw2.DoWork += (p, m) => { MoreMessages(); }; bw2.RunWorkerAsync(); private void MoreMessages() { foreach (var i in builder.ConcreateDialogCreater(ids)) { disp.Invoke(() => ReadyCollection.Insert(0, i)); } Datas.offset += 200; } где builder.ConcreateDialogCreater(ids) возвращает ObservableCollection Xaml: Так вот в этом случае при открытии окна, оно у меня некоторое время остается пустым, после чего список мгновенно отображает все объекты в ReadyCollection. От Insert это не зависит, с Add тоже самое. Также это не зависит от builder.ConcreateDialogCreater(ids), потому что пробовал делать просто инициализацию объекта при добавлении в цикле ReadyCollection.Add(new MessageChild()); Аналогичная история-объекты вываливаются всем скопом по окончании добавления последнего. А я хочу добиться постепенной подгрузки, как в предыдущем окне. Почему так происходит и что нужно исправить? UPD: Продебажил еще раз - все таки я был не прав и задержка связана с выполнением метода builder.ConcreateDialogCreater(ids). И пока он не выполнится весь- foreach не начнется. Ведь в первом случае я коллекцию заполняю непосредственно в том классе и задержка обоснована работой библиотечных методов перед добавлением. Во-втором же случае нужно ждать,пока метод выполнится полностью.
Ответы
Ответ 1
В DoWork вместо Dispatcher используйте ReportProgress. (для его работы надо включить WorkerReportsProgress). partial class MainWindow : Window { public MainWindow() { this.DataContext = _List = new ObservableCollection(); } ObservableCollection _List; private void Button_Click(object sender, RoutedEventArgs e) { var w = new BackgroundWorker() { WorkerReportsProgress = true }; w.DoWork += (s, we) => { for (var i = 0; i < 50; i++) { Thread.Sleep(100); // тут что-то делаем w.ReportProgress(0, i); } }; w.ProgressChanged += (s, we) => // выполняется в основном потоке _List.Add(new Message() { Text = "t" + we.UserState }); w.RunWorkerAsync(); } class Message { public string Text { get; set; } } }
Комментариев нет:
Отправить комментарий