对于 WPF:
这是基于最佳答案的片段,使用委托意味着它非常通用。
/// <summary>
/// Invokes the Delegate directly on the main UI thread, based on the calling threads' <see cref="Dispatcher"/>.
/// NOTE this is a blocking call.
/// </summary>
/// <param name="method">Method to invoke on the Main ui thread</param>
/// <param name="args">Argumens to pass to the method</param>
/// <returns>The return object of the called object, which can be null.</returns>
private object InvokeForUiIfNeeded(Delegate method, params object[] args)
{
if (method == null) throw new ArgumentNullException(nameof(method));
var dispatcher = Application.Current.Dispatcher;
if (dispatcher.Thread != Thread.CurrentThread)
{
// We're on some other thread, Invoke it directly on the main ui thread.
return dispatcher.Invoke(method, args);
}
else
{
// We're on the dispatchers' thread, which (in wpf) is the main UI thread.
// We can safely update ui here, and not going through the dispatcher which safes some (minor) overhead.
return method.DynamicInvoke(args);
}
}
/// <inheritdoc cref="InvokeForUiIfNeeded(Delegate, object[])"/>
public TReturn InvokeForUiIfNeeded<TReturn>(Delegate method, params object[] args)
=> (TReturn) InvokeForUiIfNeeded(method, args);
第二种方法允许更安全的返回类型。我还添加了一些重载,它们会在我的代码中自动采用Func
andAction
参数,例如:
/// <inheritdoc cref="InvokeForUiIfNeeded(System.Delegate, object[])"/>
private void InvokeForUiIfNeeded(Action action)
=> InvokeForUiIfNeeded((Delegate) action);
笔记; 和继承自Func
所以我们可以直接转换它。Action
Delegate
您还可以添加自己的通用重载来执行操作,我没有费心创建一堆重载,但您绝对可以,例如;
/// <inheritdoc cref="InvokeForUiIfNeeded(System.Delegate, object[])"/>
private void InvokeForUiIfNeeded<T1>(Action<T1> action, T1 p1)
=> InvokeForUiIfNeeded((Delegate)action, p1);
/// <inheritdoc cref="InvokeForUiIfNeeded(System.Delegate, object[])"/>
private TReturn InvokeForUiIfNeeded<T1, TReturn>(Func<T1, TReturn> action, T1 p1)
=> (TReturn)InvokeForUiIfNeeded((Delegate)action, p1);