#c_sharp #многопоточность #mvvm #backgroundworker
Пишу программу на C# с mvvm. У меня есть два эквивалентных куска кода, в которых,по-моему
мнению, должна происходить абсолютно одинаковая работа. Суть в чем- постепенная подгрузка(добавление)
элементов в коллекцию с помощью BackgroundWorker. Коллекция имеет биндинг с listview
и соответственно постепенное(пообъектное) добавление в коллекцию отображается в этом
listview.
Код:
public class ListContactViewModel : ViewModelBase
{
public ObservableCollection DialogListFirstPage { 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; } } }
Комментариев нет:
Отправить комментарий