【发布时间】:2020-05-27 05:59:58
【问题描述】:
我正在开发一个 WPF 应用程序,它的业务逻辑由类库(没有 MVVM)处理。业务逻辑的大多数属性都是依赖属性,它允许将数据轻松绑定到 WPF UI。
我有一个显示项目集合(类的依赖属性)的数据网格:ObservableCollection<ItemEntry> EntryCollection。
目标是为 EntryCollection 中的每个项目异步调用 ItemEntryUpdateAnalyzer.Analyze(ItemTemplate, Company, entry) 静态方法,因为处理需要几秒钟。
我开始做以下事情:
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");
}
效果很好,但是添加处理方法会在 ItemTemplate 的依赖属性上引发 System.InvalidOperationException
private void AnalyzeItemEntries(ItemEntry entry)
{
Log.Debug("Begin");
ItemEntryUpdateAnalyzer.Analyze(ItemTemplate, Company, entry); //InvalidOperationException
Log.Debug("End");
}
这是因为 Analyze 方法的参数属于主 UI 线程。所以我尝试使用调度程序通过执行以下操作来提供正确的上下文:
private void AnalyzeItemEntries(ItemEntry entry)
{
Log.Debug("Begin");
/*tried with InvokeAsync as well*/
Dispatcher?.BeginInvoke((Action) (() =>
{
ItemEntryUpdateAnalyzer.Analyze(ItemTemplate, Company, entry);
}));
Log.Debug("End");
}
但这并没有真正帮助,因为这会锁定主线程。问题是参数通过依赖属性绑定到 UI,普通属性似乎不会抛出异常。
编辑:
我尝试使用 DeepCloner NuGet (https://github.com/force-net/DeepCloner) 将 ItemTemplate 和 ItemEntry 深度复制到局部变量:
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 无效。
【问题讨论】:
-
一个异常有一个堆栈跟踪,检查它以获取有关错误发生位置/原因的更多详细信息。
-
这不是答案,但是当您出于好奇将
.ConfigureAwait( false );添加到WhenAll时会发生同样的情况吗? -
我也试过加
.ConfigureAwait(false),可惜没用。 -
@XAMIMAX :UI 元素未在
Analyze方法中传递。 UI 控件绑定到位于ItemTemplate和ItemEntry对象中的 Dependency 属性。这算不算糟糕的设计? -
当时ItemTemplate的实现和item entry是怎样的?如果这些是您的模型/视图模型,那么您将不需要 DP?通常的 INPC 就足够了。您是否使用这些道具的先前值?这就是为什么你会在模型上使用 DP。或者您是否将 xaml 中的值绑定到您的模型?
标签: wpf asynchronous task dependency-properties dispatcher