簡體   English   中英

在 WPF 調度程序調用中等待

[英]await inside a WPF Dispatcher call

在傳遞給調度程序的委托中確保錯誤處理的最佳解決方案是什么?

簡而言之:我需要在將計算解析為 Foo 后返回一個數字。 該計算非常緩慢,必須在 UI 線程上完成。 計算必須作為Task<string>交給另一個類。

我能想出的唯一解決方案是 CallFooWithATask___3 - 甚至不確定..

public class Foo
{
    public void CallMeWithATaskThatIsFinishedWhenTheUIIsUpdated(Task<string> task) { }
}

// CallFooWithATask___ is invoked from unknown thread. Can't wait for GetWithSideEffects on calling thread
public class SomeClass
{
    private TextBox textBox;

    public int CallFooWithATask___1(Foo foo)
    {
        // not good - async void -> no error handling
        var tcs = new TaskCompletionSource<string>();
        Dispatcher.CurrentDispatcher.BeginInvoke(async () =>
        {                
            var a = await GetWithSideEffects();
            textBox.Text = a;
            tcs.SetResult(a);
        });

        // quite fast - probally put it in a queue and returns
        foo.CallMeWithATaskThatIsFinishedWhenTheUIIsUpdated(tcs.Task);

        return 1;
    }

    public async Task<int> CallFooWithATask___2(Foo foo)
    {
        // not good - still async void  -> no error handling .. when is foo actually called? I assume when hitting the inner await'ish?
        var task =  await Dispatcher.CurrentDispatcher.InvokeAsync(async () =>
        {
            var a = await GetWithSideEffects();
            textBox.Text = a;
            return a;
        });

        // quite fast - probally put it in a queue and returns
        foo.CallMeWithATaskThatIsFinishedWhenTheUIIsUpdated(task);

        return 1;
    }

    public int CallFooWithATask___3(Foo foo)
    {
        // what is the elegant solution - probally not this?
        var tcs = new TaskCompletionSource<string>();
        Dispatcher.CurrentDispatcher.BeginInvoke(async () =>
        {
            try
            {
                var a = await GetWithSideEffects();
                textBox.Text = a;
                tcs.SetResult(a);
            }
            catch (Exception ex) { tcs.SetException(ex); }
        });

        // quite fast - probally put it in a queue and returns
        foo.CallMeWithATaskThatIsFinishedWhenTheUIIsUpdated(tcs.Task);

        return 1;
    }

    // this might trigger ui updates and is very slow ..
    private Task<string> GetWithSideEffects()=> Task.FromResult("42");
}

你很接近。 只需在方法或Func<Task<string>>提取異步代碼,以避免以async void結尾:

Func<Task<string>> func = async () =>
{
    var a = await GetWithSideEffects();

    return a;
};

然后使用InvokeAsync調用它。 你最終會得到一個Task<Task<string>> 內部任務是異步方法返回的任務,外部任務是InvokeAsync生成的InvokeAsync用於指示實際調度調用的時間。 使用.Unwrap合並這些任務,最后將它們發送到你的另一個方法:

var task = Dispatcher.InvokeAsync(func).Task.Unwrap();

foo.CallMeWithATaskThatIsFinishedWhenTheUIIsUpdated(task);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM