如何将任务优先切换到WPF Dispatcher?

问题描述 投票:0回答:1

WPF Dispatcher 有一个方法 InvokeAsync,它接受

Action
Func<T>
DispatcherPriority

我需要通过

Func<Task<T>>
并且我需要在具有给定优先级的 WPF 调度程序上运行整个
Task<T>

示例:

我需要调用一个必须在调度程序线程上运行的异步函数

Foo

async Task<SomeResult> Foo()
{
    // some view model modification that needs to run on UI thread
    ...

    // calling some IO call on thread pool
    await Task.Run(() => SomeIoCallAsync()); 

    // more view model modifications
    ...

    // calling something on thread pool
    await Task.Run(() => HeavyComputation());

    // more view model modifications
    ...

    return someResult;
}

来自不在 UI 线程上运行的异步函数

Bar

async Task<SomeOtherResult> Bar()
{
    ...

    TODO call Foo() on UI thread

    ...

}

注意:如果

Foo
不是异步函数而只是同步函数,则
Bar
可能如下所示:

async Task<SomeOtherResult> Bar()
{
    ...

    await dispatcher.InvokeAsync(Foo, someDispatcherPriority);

    ...

}

如何在调度程序线程上以某种优先级调用异步函数?

c# wpf async-await dispatcher
1个回答
0
投票

假设您实际上需要从方法

SomeResult
返回的
Foo()
值,您有两种选择。致电
await InvokeAsync
或直接拨打
Invoke

在这两种情况下,

Foo
都在UI线程上启动,并且返回的
Task<SomeResult>
在您调用调度程序的线程中等待:

Task<SomeResult> task = await dispatcher.InvokeAsync(Foo, someDispatcherPriority);
SomeResult result = await task;

SomeResult result = await dispatcher.Invoke(Foo, someDispatcherPriority);

这里是一个代码示例,展示了它是如何工作的。

status
是主窗口 XAML 中的 TextBlock。

class SomeResult
{
    public int ThreadId { get; set; }
}

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    async Task<SomeResult> Foo()
    {
        status.Text = $"Foo started in thread {Environment.CurrentManagedThreadId}";

        var id1 = await Task.Run(() =>
        {
            Thread.Sleep(2000);
            return Environment.CurrentManagedThreadId;
        });

        status.Text = $"First Task ran in thread {id1}";

        var id2 = await Task.Run(() =>
        {
            Thread.Sleep(2000);
            return Environment.CurrentManagedThreadId;
        });

        status.Text = $"Second Task ran in thread {id2}";

        return new SomeResult { ThreadId = Environment.CurrentManagedThreadId };
    }

    async void Window_Loaded(object sender, RoutedEventArgs e)
    {
        await Task.Run(async () =>
        {
            var id = Environment.CurrentManagedThreadId;

            Dispatcher.Invoke(() => status.Text = $"Main Task started in thread {id}");

            await Task.Delay(2000);

            SomeResult result = await Dispatcher.Invoke(Foo, DispatcherPriority.Normal);

            await Task.Delay(2000);

            Dispatcher.Invoke(() => status.Text = $"Foo ended in thread {result.ThreadId}");
        });
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.