使用 WinForms ProgressBar 进行异步/等待 [英] Async/Await with a WinForms ProgressBar

查看:16
本文介绍了使用 WinForms ProgressBar 进行异步/等待的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我过去曾使用 BackgroundWorker 处理过此类问题,但我想使用 .NET 4.5 的新异步/等待方法.我可能在吠错树.请指教.

I've gotten this type of thing working in the past with a BackgroundWorker, but I want to use the new async/await approach of .NET 4.5. I may be barking up the wrong tree. Please advise.

目标:创建一个组件,该组件将执行一些长期运行的工作,并在执行工作时显示带有进度条的模态表单.组件会在执行长时间运行的工作时获取窗口句柄以阻止交互.

Goal: Create a component that will do some long-running work and show a modal form with a progress bar as it's doing the work. The component will get the handle to a window to block interaction while it's executing the long-running work.

状态:请参阅下面的代码.我以为我做得很好,直到我尝试与窗户互动.如果我不理会(即不要碰!),一切都会完美"运行,但是如果我只点击任一窗口,程序会在长时间运行的工作结束后挂起.实际交互(拖动)会被忽略,就像 UI 线程被阻止一样.

Status: See the code below. I thought I was doing well until I tried interacting with the windows. If I leave things alone (i.e. don't touch!), everything runs "perfectly", but if I do so much as click on either window the program hangs after the long-running work ends. Actual interactions (dragging) are ignored as though the UI thread is blocked.

问题:我的代码可以很容易地修复吗?如果是这样,如何?或者,我应该使用不同的方法(例如 BackgroundWorker)吗?

Questions: Can my code be fixed fairly easily? If so, how? Or, should I be using a different approach (e.g. BackgroundWorker)?

代码(Form1 是一个标准表单,带有一个 ProgressBar 和一个公共方法 UpdateProgress,用于设置 ProgressBar 的值):

Code (Form1 is a standard form with a ProgressBar and a public method, UpdateProgress, that sets the ProgressBar's Value):

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ConsoleApplication1
{
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Starting..");
        var mgr = new Manager();
        mgr.GoAsync();
        Console.WriteLine("..Ended");
        Console.ReadKey();
    }
}

class Manager
{
    private static Form1 _progressForm;

    public async void GoAsync()
    {
        var owner = new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
        _progressForm = new Form1();
        _progressForm.Show(owner);

        await Go();

        _progressForm.Hide();
    }

    private async Task<bool> Go()
    {
        var job = new LongJob();
        job.OnProgress += job_OnProgress;
        job.Spin();
        return true;
    }

    void job_OnProgress(int percent)
    {
        _progressForm.UpdateProgress(percent);
    }
}

class LongJob
{
    public event Progressed OnProgress;
    public delegate void Progressed(int percent);

    public void Spin()
    {
        for (var i = 1; i <= 100; i++)
        {
            Thread.Sleep(25);
            if (OnProgress != null)
            {
                OnProgress(i);
            }
        }
    }
}

class Win32Window : IWin32Window
{
    private readonly IntPtr _hwnd;
    public Win32Window(IntPtr handle)
    {
        _hwnd = handle;
    }
    public IntPtr Handle
    {
        get
        {
            return _hwnd;
        }
    }
}
}

推荐答案

@StephenCleary 的回答是正确的.不过,我不得不对他的回答做一些修改,以获得我认为 OP 想要的行为.

@StephenCleary's answer is correct. Though, I had to make a little modification to his answer to get the behavior what I think OP wants.

public void GoAsync() //no longer async as it blocks on Appication.Run
{
    var owner = new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
    _progressForm = new Form1();

    var progress = new Progress<int>(value => _progressForm.UpdateProgress(value));

    _progressForm.Activated += async (sender, args) =>
        {
            await Go(progress);
            _progressForm.Close();
        };

    Application.Run(_progressForm);
}

这篇关于使用 WinForms ProgressBar 进行异步/等待的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆