Я работаю над приложением WPF, чьи бизнес-логики c обрабатываются библиотекой классов (без MVVM). Большинство свойств бизнес-логики c являются свойствами зависимостей, что позволяет легко связывать данные с пользовательским интерфейсом WPF.
У меня есть сетка данных, которая отображает коллекцию элементов (свойство зависимости класса): ObservableCollection<ItemEntry> EntryCollection
.
Цель состоит в том, чтобы асинхронно вызывать метод ItemEntryUpdateAnalyzer.Analyze(ItemTemplate, Company, entry)
stati c для каждый элемент в EntryCollection, так как обработка занимает несколько секунд.
Я начал с выполнения следующих действий:
private async void AnalyzeButton_OnClick(object sender, RoutedEventArgs e)
{
List<Task> tasks = EntryCollection.Select(entry => Task.Run(() => AnalyzeItemEntries())).ToList();
await Task.WhenAll(tasks);
}
private void AnalyzeItemEntries()
{
Log.Debug("Begin");
Thread.Sleep(500);
Log.Debug("End");
}
Это работало нормально, но добавление метода обработки вызывает исключение System.InvalidOperationException для свойства зависимостей ItemTemplate
private void AnalyzeItemEntries(ItemEntry entry)
{
Log.Debug("Begin");
ItemEntryUpdateAnalyzer.Analyze(ItemTemplate, Company, entry); //InvalidOperationException
Log.Debug("End");
}
Это связано с тем, что аргументы метода Analyze принадлежат основному потоку пользовательского интерфейса. Поэтому я попытался использовать диспетчер, чтобы получить правильный контекст, выполнив следующее:
private void AnalyzeItemEntries(ItemEntry entry)
{
Log.Debug("Begin");
/*tried with InvokeAsync as well*/
Dispatcher?.BeginInvoke((Action) (() =>
{
ItemEntryUpdateAnalyzer.Analyze(ItemTemplate, Company, entry);
}));
Log.Debug("End");
}
Но это не очень помогает, поскольку это блокирует основной поток. Проблема в том, что аргументы связывают пользовательский интерфейс с помощью свойств зависимости, обычные свойства, похоже, не выдают исключение.
РЕДАКТИРОВАТЬ:
Я пытался глубоко скопировать ItemTemplate и ItemEntry в локальные переменные, используя DeepCloner NuGet (https://github.com/force-net/DeepCloner):
private async void AnalyzeButton_OnClick(object sender, RoutedEventArgs e)
{
Log.Debug($"==== Main thread ID {Thread.CurrentThread} ===");
ItemTemplate localTemplate = ItemTemplate.DeepClone();
ObservableCollection<ItemEntry> localEntryCollection = EntryCollection.DeepClone();
foreach (ItemEntry entry in localEntryCollection)
{
await Task.Run(() => AnalyzeItemEntries(localTemplate, entry));
}
}
private void AnalyzeItemEntries(ItemTemplate template, ItemEntry entry)
{
Log.Debug($"Begin {entry.ItemCode}");
ItemEntryUpdateAnalyzer.Analyze(template, Company, entry);
Log.Debug($"End {entry.ItemCode}");
}
Я все еще получаю ту же ошибку. Кажется, что проблема связана только со свойствами зависимостей, поскольку доступ к entry.ItemCode
(стандартное свойство) работает, а доступ к entry.Action
- нет.