我设法使用Task.Run()
和Dispatcher.BeginInvoke()
的组合创建异步模式对话框。
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace WpfTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var context = SynchronizationContext.Current;
MessageBox.Show("Modal dialog on same thread. " + Thread.CurrentThread.ManagedThreadId);
// Why do these two seem to behave the same despite Task.Run() using a different thread?
Task.Run(() => MessageBox.Show("Attempted modal dialog on different thread using Task.Run(). " + Thread.CurrentThread.ManagedThreadId));
Dispatcher.BeginInvoke(new Action(() => MessageBox.Show("Attempted asynchronous modal dialog on same thread using Dispatcher.BeginInvoke(). " + Thread.CurrentThread.ManagedThreadId)));
// This behaves as desired.
Task.Run(() => Dispatcher.BeginInvoke(new Action(() => MessageBox.Show("Attempted modal dialog from different thread using Task.Run() AND Dispatcher.BeginInvoke(). " + Thread.CurrentThread.ManagedThreadId))));
// These are unreliable. They behave as desired when they're the only dialog shown.
Task.Run(() => context.Send(state => MessageBox.Show("Attempted synchronous modal dialog on same thread using SynchronizationContext.Send(). " + Thread.CurrentThread.ManagedThreadId), null));
Task.Run(() => context.Post(state => MessageBox.Show("Attempted asynchronous modal dialog on same thread using SynchronizationContext.Post(). " + Thread.CurrentThread.ManagedThreadId), null));
}
}
}
仅使用Task.Run()
时,对话框不是模态的。也就是说,在对话框打开时,主窗口仍然可以获得焦点。仅使用Dispatcher.BeginInvoke()
具有相同的行为。这是为什么?如果在主UI线程上创建对话框,为什么该对话框不是模态的?当它从另一个线程调用时,为什么它会正常工作?
此外,为什么SynchronizationContext.Post()
与[{1}}的工作方式相同,只看Dispatcher.BeginInvoke()
只调用DispatcherSynchronizationContext.Post()
?
Dispatcher.BeginInvoke()
如果有人能够对此有所了解或指出我所遗漏的任何事情,我将不胜感激。如果您想知道,我需要异步创建模式对话框的原因是因为我需要不阻止UI线程,因为代码实际上是从 /// <summary>
/// Asynchronously invoke the callback in the SynchronizationContext.
/// </summary>
public override void Post(SendOrPostCallback d, Object state)
{
// Call BeginInvoke with the cached priority. Note that BeginInvoke
// preserves the behavior of passing exceptions to
// Dispatcher.UnhandledException unlike InvokeAsync. This is
// desireable because there is no way to await the call to Post, so
// exceptions are hard to observe.
_dispatcher.BeginInvoke(_priority, d, state);
}
控件中运行的ActionScript调用的,它会抛出脚本超时错误,如果它认为它执行了很长时间。