2

我正在开发一个 WPF XBAP 应用程序,它使用 BrowserInteropHelper 通过 JavaScript 向用户提供 API。在以新的 async-await 方式重写托管部分后,需要等待异步操作完成,而不使调用方法 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 是 async 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;    
}
4

3 回答 3

2

在以新的 async-await 方式重写托管部分后,需要等待异步操作完成,而不使调用方法 async Task 本身。

这是您可以尝试做的最困难的事情之一。

AsyncMethod 是 async Task< T > 并且在从应用程序内部(即在某个按钮处理程序内部)执行和等待时可以完美运行。它有很多依赖于 UI 的逻辑

而这种情况几乎是不可能的。


问题是您需要阻止SyncMethod在 UI 线程上运行的线程,同时允许AsyncMethod调度到 UI 消息队列。

您可以采取以下几种方法:

  1. 阻止Task使用Waitor Result。您可以通过使用in来避免我的博客中描述的死锁问题。这意味着必须重构以依赖于 UI 的逻辑替换为其他非阻塞回调。ConfigureAwait(false)AsyncMethodAsyncMethodIProgress<T>
  2. 安装嵌套消息循环。这应该可行,但您必须考虑所有重入的后果。

就个人而言,我认为(1)更干净。

于 2012-10-22T15:00:01.963 回答
0

做这个:

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() 的 finally 块时发生。

于 2012-10-22T13:52:24.913 回答
-1

这为我解决了。

为调用者添加任务延迟完成

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;        
}
于 2018-11-12T14:47:28.417 回答