这是一种启动匿名任务并继续ui线程的好方法吗?

本文关键字:线程 ui 继续 方法 任务 启动 一种 | 更新日期: 2023-09-27 18:12:32

我已经有一段时间没有使用任务和lambda表达式了。这是一个好方法来运行一个匿名任务与lambda表达式,然后在UI线程上运行代码时,任务完成?

private void btn_mods_Click(object sender, RoutedEventArgs e)
{
    function_buttons_stackpanel.IsEnabled = false;
    Loading();
    Task task = new Task(() => {
        if (IsServiceIsUp() != false)
        {
            webServiceMods = JsonConvert.DeserializeObject(_webServiceResponse).mods;
            webServiceBaseUrl = JsonConvert.DeserializeObject(_webServiceResponse).basePath;
            Console.Write(webServiceBaseUrl);
        }
    });
    task.Start();
    task.ContinueWith((foo) =>
    {
        FinishedLoading();
        function_buttons_stackpanel.IsEnabled = true;
    }, TaskScheduler.FromCurrentSynchronizationContext());
}
private void Loading()
{
    img_loading.Visibility = Visibility.Visible;
}
private void FinishedLoading()
{
    img_loading.Visibility = Visibility.Collapsed;
}
我试图将任务链接起来。直接启动,但这给了我一个错误Cannot Implicitly convert type void to System.Threading.Tasks.Task

基本上我想做的是从头到尾链接整个过程。

Task task = new Task(() => {
    if (IsServiceIsUp() != false)
    {
        webServiceMods = JsonConvert.DeserializeObject(_webServiceResponse).mods;
        webServiceBaseUrl = JsonConvert.DeserializeObject(_webServiceResponse).basePath;
        Console.Write(webServiceBaseUrl);
    }
}).Start();
在PHP中,我将这样做:
$task = new Task(() => {
    if (IsServiceIsUp() != false)
    {
        $webServiceMods = JsonConvert::DeserializeObject($_webServiceResponse).mods;
        $webServiceBaseUrl = JsonConvert::DeserializeObject($_webServiceResponse).basePath;
        Console::Write($webServiceBaseUrl);
    }
})
->Start()
->ContinueWith(($foo) =>
{
    FinishedLoading();
    $function_buttons_stackpanel.IsEnabled = true;
}, TaskScheduler::FromCurrentSynchronizationContext());

这可能吗?如果是这样,有什么理由不这样做,如果有更好的方法,你能给我举个例子吗?

,谢谢!

这是一种启动匿名任务并继续ui线程的好方法吗?

您可以很容易地做到这一点,使用async-await:

private async void btn_mods_Click(object sender, RoutedEventArgs e)
{
    if (!IsServiceIsUp())
        return;
    function_buttons_stackpanel.IsEnabled = false;
    Loading();
    await Task.Run(() => 
    {
        var result = JsonConvert.DeserializeObject(_webServiceResponse);
        Console.Write(result.webServiceBaseUrl);
    });
    FinishedLoading();
    function_buttons_stackpanel.IsEnabled = true;
}

性能方面,我不确定您是否需要使用线程池线程来反序列化JSON。我肯定会测试这段代码,以确定它是否值得。

如果您将事件处理程序声明为异步函数,则不必启动任务,因为它已经异步运行。

所有异步函数应该返回Task而不是void和Task <TResult>而不是result。唯一的例外是事件处理程序。事件处理程序返回void

在正确的async-await中应该是这样的:

private async void btn_mods_Click(object sender, RoutedEventArgs e)
{
    function_buttons_stackpanel.IsEnabled = false;
    Loading();
    if (IsServiceIsUp())
    {   // The service is up, start the deserialization
        // because this function is async, you can call other async functions
        // without having to start a task
        // The UI remains responsive
        webServiceMods = await JsonConvert.DeserializeObjectAsync(_webServiceResponse).mods;
        // because of the await above, the second task is started after the first is finished:
        webServiceBaseUrl = await JsonConvert.DeserializeObjectAsync(_webServiceResponse).basePath;
        // because of the await the second task is also finished            
        Console.Write(webServiceBaseUrl);
        FinishedLoading();
        function_buttons_stackpanel.IsEnabled = true;
    }
}
通过让你的事件处理程序异步,你的代码将充分利用async-await。在async-await时代之前,如果没有continueWith和其他Task相关函数的魔力,你的代码会看起来整洁得多。

最后一点:下面的代码看起来很傻,而且没有必要困难:

if (IsServiceIsUp() != false) ...

当然应该是:

if (IsServiceIsUp()) ...