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