使用 Async/Await 时的 WPF ProgressBar 用法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26285926/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 12:35:53  来源:igfitidea点击:

WPF ProgressBar usage when using Async/Await

c#wpf

提问by user1166905

I have a very simple task that loads some data like so:

我有一个非常简单的任务,它加载一些数据,如下所示:

async Task<List<Invoice>> GetInvoices()
{
    var invoices = await Task.Run(() => db.Invoices.AsNoTracking().ToList());
    return invoices;
}

What would be the best way to use this with a progressbar? I don't need to get the percentage loaded (although that would be useful), I simply need to show/hide the progressbar at start and finish of loading data. Is there a way to create a completed or finished method perhaps?

将它与进度条一起使用的最佳方法是什么?我不需要加载百分比(尽管这很有用),我只需要在加载数据的开始和结束时显示/隐藏进度条。有没有办法创建一个完成或完成的方法?

I am very new to async/await so kid gloves please!

我对 async/await 很陌生,所以请戴手套!

回答by Sebastian Negraszus

Assuming GetInvoicesgets called in some UI event handler and there is some progress bar control called ProgressBar, it's really simple:

假设GetInvoices在一些 UI 事件处理程序中被调用,并且有一些名为 的进度条控件ProgressBar,它真的很简单:

private async void OnButton1Click(..)
{
    ProgressBar.IsIndeterminate = true;
    var result = await GetInvoices();
    ProgressBar.IsIndeterminate = false; // Maybe hide it, too
    // TODO: Do stuff with result
}

If you want to show actual progress, take a look at Progress<T>and IProgress<T>.

如果您想显示实际进度,请查看Progress<T>IProgress<T>

回答by Patrick

You already have what you need. To illustrate here's a simple example with tasks and using await, and ContinueWith.

你已经有了你需要的东西。为了说明这里有一个简单的例子,任务和使用 await 和 ContinueWith。

using System;
using System.Threading.Tasks;
using System.Diagnostics;
public class Program
{
    public static void Main()
    {
        Task t = new Program().TestTasks();
        Console.WriteLine("hello");
        t.Wait();
    }

    public async Task TestTasks()
    {
        Stopwatch watch = Stopwatch.StartNew();
        Console.WriteLine("1." + watch.ElapsedMilliseconds);
        // await task
        int res = await TestAsync();
        Console.WriteLine("2." + watch.ElapsedMilliseconds + " " + res);
        // save task and wait on it
        Task<int> t = TestAsync();
        t.ContinueWith((r) =>
        {
            Console.WriteLine("4." + watch.ElapsedMilliseconds + " " + r.Result);
        });
        Console.WriteLine("3." + watch.ElapsedMilliseconds);
        t.Wait();
    }

    public static async Task<int> TestAsync()
    {
        await Task.Delay(TimeSpan.FromSeconds(2));
        return 42;
    }
}

This prints:

这打印:

1.0
hello
2.2009 42
3.2009
4.4013 42
1.0
hello
2.2009 42
3.2009
4.4013 42

Note how the await leaves the method and prints "hello" in the Main method, and after (about) 2 seconds continue in the TestTasks method. On the other hand, if we do notawait, as the second call to TestAsync shows, 3. is printed immediately, and after 2 seconds, 4. is printed.

请注意 await 如何离开该方法并在 Main 方法中打印“hello”,并在(大约)2 秒后在 TestTasks 方法中继续。另一方面,如果我们等待,如对 TestAsync 的第二次调用所示, 3. 立即打印,2 秒后, 4. 打印。

With this in mind, you can just call your method GetInvoiceswith await since you're returning a Task.

考虑到这一点,您可以GetInvoices使用 await调用您的方法,因为您要返回一个任务。

// Set state of progressbar to indeterminate
List<Invoice> result = await GetInvoices();
// Set state of progressbar to nothing

回答by Tigran

You can do something like:

您可以执行以下操作:

var task = Task.Run(() => db.Invoices.AsNoTracking().ToList()); 

//show progress

task.ContinueWith(...CLOSE PROGRESS BAR...);

In practise you use Task.ContinueWithconstruct to catch the termination of the task and hide a progress bar you have shown before.

在实践中,您使用Task.ContinueWith构造来捕获任务的终止并隐藏您之前显示的进度条。

Note: keep in mind that acting on UI element from another thread requires Invoke()call, as that call redirects actual invokation to the main thread, which is a only thread were UI controls can be operated on windows.

注意:请记住,从另一个线程处理 UI 元素需要Invoke()调用,因为该调用将实际调用重定向到主线程,这是唯一一个可以在 Windows 上操作 UI 控件的线程。