![](/img/trans.png)
[英]Returning a value from Dispatcher.RunAsync() to background thread
[英]Returning value from async Action invoked on Dispatcher
我正在开发一个WPF XBAP应用程序,该应用程序通过使用BrowserInteropHelper通过JavaScript向用户提供API。 在以新的异步等待方式重写托管部分之后,需要等到异步操作完成后才能使调用方法async Task本身不进行调用。 我有 :
public string SyncMethod(object parameter)
{
var sender = CurrentPage as MainView; // interop
var result = string.Empty;
if (sender != null)
sender.Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(async () =>
{
try
{
result = await sender.AsyncMethod(parameter.ToString());
}
catch (Exception exception)
{
result = exception.Message;
}
}));
return result;
}
此方法返回string.Empty,因为它在执行后立即发生。 我试图将此操作分配给DispatcherOperation并执行while(dispatcherOperation.Status!= Completed){Wait(); },但即使执行后该值仍为空。 dispatcherOperation.Task.Wait()或dispatcherOperation.Task.ContinueWith()也没有帮助。
编辑
也尝试过
var op = sender.Dispatcher.BeginInvoke(...);
op.Completed += (s, e) => { var t = result; };
但是t也为空,因为赋值发生在等待异步方法之前。
编辑
长话短说,SyncMethod JavaScript互操作处理程序帮助程序包装器及其运行的所有操作必须在Dispatcher上。 AsyncMethod是异步Task <T>,当在应用程序内部(即在某些按钮处理程序内部)执行并等待时,可以完美地工作。 它具有许多依赖于UI的逻辑(显示状态进度栏,更改光标等)。
编辑
AsyncMethod:
public async Task<string> AsyncMethod(string input)
{
UIHelpers.SetBusyState(); // overriding mouse cursor via Application.Current.Dispatcher
ProgressText = string.Empty; // viewmodel property reflected in ui
var tasksInputData = ParseInput(input);
var tasksList = new List<Task>();
foreach (var taskInputDataObject in tasksInputData)
{
var currentTask = Task.Factory.StartNew(() =>
{
using (var a = new AutoBusyHandler("Running operation" + taskInputData.OperationName))
{ // setting busy property true/false via Application.Current.Dispatcher
var databaseOperationResult = DAL.SomeLongRunningMethod(taskInputDataObject);
ProgressText += databaseOperationResult;
}
});
tasksList.Add(insertCurrentRecordTask);
}
var allTasksFinished = Task.Factory.ContinueWhenAll(tasksList.ToArray(), (list) =>
{
return ProgressText;
});
return await allTasksFinished;
}
在以新的异步等待方式重写托管部分之后,需要等到异步操作完成后才能使调用方法async Task本身不进行调用。
这是您可以尝试做的最困难的事情之一。
AsyncMethod是异步Task <T>,当在应用程序内部(即在某些按钮处理程序内部)执行并等待时,可以完美地工作。 它具有很多依赖于UI的逻辑
这种情况几乎是不可能的。
问题是,你需要阻止SyncMethod
这是在UI线程上运行,同时允许AsyncMethod
派遣到UI消息队列。
您可以采取几种方法:
Wait
或Result
阻止Task
。 您可以通过在AsyncMethod
使用ConfigureAwait(false)
来避免博客上描述的死锁问题 。 这意味着AsyncMethod
将必须进行重构,以取代相关的UI逻辑IProgress<T>
或其他非阻塞回调。 我个人认为(1)更清洁。
做这个:
var are = new AutoResetEvent(true);
sender.Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(async () =>
{
try { ... } catch { ... } finally { are.Set(); }
}));
are.WaitOne();
return result;
are.WaitOne()将告诉AutoResetEvent等待,直到发出信号为止,这将在调度程序动作最终到达调用are.Set()的块时发生。
这为我解决了。
public string SyncMethod(object parameter)
{
var sender = CurrentPage as MainView; // interop
var result = string.Empty;
if (sender != null)
{
await sender.Dispatcher.Invoke(DispatcherPriority.Normal,
new Func<Task>(async () =>
{
try
{
result = await sender.AsyncMethod(parameter.ToString());
}
catch (Exception exception)
{
result = exception.Message;
}
}));
}
await Task.Delay(200); // <-- Here
return result;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.