Я имею контроль, которому связали его данные со стандартом ObservableCollection
, и у меня есть фоновая задача, которая называет сервис для получения большего количества данных.
Я хочу, затем, обновите мои данные поддержки позади моего управления при отображении, "ожидайте" диалоговое окно, но когда я добавляю новые объекты к набору, поток UI запирается, в то время как это снова переплетает и обновляет мои средства управления.
Я могу обойти это так, чтобы мои анимации и материал продолжали бежать на мой, "ожидайте" диалоговое окно?
Или, по крайней мере, дайте "появление" пользователю что не запертый?
Если я правильно понимаю, вы уже используете BackgroundWorker для получения данных, и простое присвоение этих данных ObservableCollection блокирует UI.
Один из способов избежать блокировки пользовательского интерфейса - назначить данные ObservableCollection меньшими порциями, поставив в очередь несколько методов диспетчера. Между каждым вызовом метода могут обрабатываться события пользовательского интерфейса.
следующее будет добавлять по одному элементу за раз, это немного экстремально, но это иллюстрирует концепцию.
void UpdateItems()
{
//retrievedItems is the data you received from the service
foreach(object item in retrievedItems)
Dispatcher.BeginInvoke(DispatcherPriority.Background, new ParameterizedThreadStart(AddItem), item);
}
void AddItem(object item)
{
observableCollection.Add(item);
}
используйте BackgroundWorker для выполнения этой задачи. обновите коллекцию obsrvablecollection в методе DoWork
ObservableCollection будет вызывать события CollectionChanged, которые заставят UI перепривязать данные, измерить, расположить и перерисовать. Это может занять много времени, если у вас много обновлений.
Можно заставить пользователя думать, что UI жив, разделив работу на небольшие пакеты. Используйте диспетчер из потока UI (любой элемент управления имеет ссылку на него) для планирования действий по обновлению коллекции из 10-100 элементов (определите число экспериментальным путем, это просто для поддержки идеи).
Ваш фоновый код может выглядеть так:
void WorkInBackground()
{
var results = new List<object>();
//get results...
// feed UI in packages no more than 100 items
while (results.Count > 0)
{
Application.Current.MainWindow.Dispatcher.BeginInvoke(
new Action<List<object>>(FeedUI),
DispatcherPriority.Background,
results.GetRange(0, Math.Min(results.Count, 100)));
results.RemoveRange(0, Math.Min(results.Count, 100));
}
}
void FeedUI(List<object> items)
{
// items.Count must be small enough to keep UI looks alive
foreach (var item in items)
{
MyCollection.Add(item);
}
}
Используйте это:
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Render, new Action(UpdateData), value);
private void UpdateData(int value)
{
BindingSourceProperty = value;
}