gpt4 book ai didi

c# - 使用 WinForms ProgressBar 异步/等待

转载 作者:可可西里 更新时间:2023-11-01 02:58:45 26 4
gpt4 key购买 nike

我在过去使用 BackgroundWorker 时遇到过此类问题,但我想使用 .NET 4.5 的新异步/等待方法。我可能找错人了。请指教。

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

状态:见下面的代码。在我尝试与 window 互动之前,我认为我做得很好。如果我放任不管(即不要触摸!),一切都会“完美”运行,但如果我只是点击任一窗口,程序就会在长时间运行的工作结束后挂起。实际交互(拖动)将被忽略,就好像 UI 线程被阻止一样。

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

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

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;
}
}
}
}

最佳答案

asyncawait关键字并不意味着“在后台线程上运行”。我有一个 async / await intro on my blog描述他们的意思。您必须明确地将 CPU 绑定(bind)操作放在后台线程上,例如 Task.Run .

另外,Task-based Asynchronous Pattern文档描述了 async 的常用方法代码,例如进度报告。

class Manager
{
private static Form1 _progressForm;

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

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

_progressForm.Hide();
}

private Task<bool> Go(IProgress<int> progress)
{
return Task.Run(() =>
{
var job = new LongJob();
job.Spin(progress);
return true;
});
}
}

class LongJob
{
public void Spin(IProgress<int> progress)
{
for (var i = 1; i <= 100; i++)
{
Thread.Sleep(25);
if (progress != null)
{
progress.Report(i);
}
}
}
}

请注意 Progress<T> type 正确处理线程编码(marshal)处理,因此不需要在 Form1.UpdateProgress 中进行编码(marshal)处理.

关于c# - 使用 WinForms ProgressBar 异步/等待,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17972268/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com