我从以下语句中得到了我对任务内部可用的外部 lambda 参数的期望,但是 FrameworkElement 转换对象的某些属性(包括名称)抛出 System.InvalidOperationException。外层 lambda 中没有这样的错误。
Targets.AddHandler(CommandManager.ExecutedEvent,
(ExecutedRoutedEventHandler) ((s,e) =>
Task.Run(() =>
MessageBox.Show(string.Format("Targets {0} {1}",
((FrameworkElement)s).Name, e.RoutedEvent.Name))))
, true);
这是 ((FrameworkElement)s).Name
在任务中的监视部分...
我猜这是线程问题?
错误的原因是什么?将我需要的值传递到任务中的最佳方法是什么?
解决方案
正如@Mercer 所解释的,我需要处理DependencyObject
的线程关联。正如答案中所述,它继承自 DispatcherObject
,因此 - 只是为了问题的完整性 - 如果有必要,我可以充分利用它来获取属性的实时值。
Targets.AddHandler(CommandManager.ExecutedEvent,
(ExecutedRoutedEventHandler) (async (s, e) =>
await Task.Run(() =>
{
var source = s as FrameworkElement;
string elementName = "null";
source.Dispatcher.Invoke(() =>
elementName = source.Name
);
MessageBox.Show(string.Format("Targets {0} {1}",
elementName, e.RoutedEvent.Name));
})
)
, true
);
关于我在下面的评论中提出的问题,根据建议的阅读,我想等待任务是一个好主意的原因是与线程生命周期有关。
我尝试了上面的异步版本,在任务中使用 Thread.Sleep 调用并将其与删除异步和等待的相同内容进行比较。它表现相同。包含上述代码的窗口是从主窗口启动的,如果我启动任务并关闭子窗口,让主窗口继续运行,MessageBox 仍会在 sleep 期后显示。如果我也关闭主机窗口,则在任务完成之前,进程终止并且 MessageBox 不显示。
我不知道这两种情况下是否存在任何内存泄漏,但我认为等待任务的做法是为了消除这种风险。
最佳答案
从后台线程(如运行任务的线程),您无法访问在应用程序的 UI 线程中创建的 DependencyObjects 的依赖属性。这是因为 DependencyObjects 是 DispatcherObjects,因此具有线程关联性。
带有按钮单击处理程序的简单示例:
<Button Content="Click" Click="OnButtonClick"/>
以下 Click 处理程序方法抛出 InvalidOperationException:
private async void OnButtonClick(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
await Task.Run(() => MessageBox.Show((string)button.Content));
}
虽然这个不会:
private async void OnButtonClick(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
var content = (string)button.Content;
await Task.Run(() => MessageBox.Show(content));
}
我想在您的场景中,不等待任务也是可以的:
private void OnButtonClick(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
var content = (string)button.Content;
Task.Run(() => MessageBox.Show(content));
}
关于c# - Task 和 FrameworkElement 参数的词法绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41510725/