异步/等待着一个WinForms进度 [英] Async/Await with a WinForms ProgressBar
问题描述
我已经得到这种类型的与一个BackgroundWorker过去工作的事情,但我想用新的异步/等待的.NET 4.5的方法。我可能会找错了树。请指教。
目标:创建一个组成部分,因为它是做的工作,会做一些长时间运行工作,并显示模式窗体有一个进度条。该组件将获得句柄到窗口阻止互动,而它的执行长时间运行的工作。
状态:请参见下面的code。我认为我做得很好,直到我试图与Windows交互。如果我离开孤独的事情(即不碰!),一切运行完美,但如果我做了这么多的点击任一窗口中的程序长时间运行的工作结束后悬。实际相互作用(拖)被忽略,虽然UI线程被阻塞。
问题:可我code可以很容易解决吗?如果是这样,怎么样?或者,我应该使用不同的方法(例如BackgroundWorker的)?
code (Form1上是一个标准的形式与进度和公共方法,的UpdateProgress中,设定进度的值):
使用系统;
使用System.Diagnostics程序;
使用的System.Threading;
使用System.Threading.Tasks;
使用System.Windows.Forms的;命名空间的ConsoleApplication1
{
类节目
{
静态无效的主要(字串[] args)
{
Console.WriteLine(启动..);
VAR经理=新管理器();
mgr.GoAsync();
Console.WriteLine(..已结束);
Console.ReadKey();
}
}一流的管理
{
私有静态Form1中_progressForm; 公共异步无效GoAsync()
{
VAR所有者=新Win32Window(Process.GetCurrentProcess()MainWindowHandle);
_progressForm =新Form1的();
_progressForm.Show(所有者); 等待围棋(); _progressForm.Hide();
} 私人异步任务<布尔>走()
{
VAR工作=新LongJob();
job.OnProgress + = job_OnProgress;
job.Spin();
返回true;
} 无效job_OnProgress(INT百分比)
{
_progressForm.UpdateProgress(百分比);
}
}类LongJob
{
公共事件进展OnProgress;
公共委托无效进展(INT%)的; 公共无效旋转()
{
对于(VAR I = 1; I< = 100;我++)
{
Thread.sleep代码(25);
如果(OnProgress!= NULL)
{
OnProgress(ⅰ);
}
}
}
}类Win32Window:IWin32Window
{
私人只读的IntPtr _hwnd;
公共Win32Window(IntPtr的手柄)
{
_hwnd =手柄;
}
公众的IntPtr句柄
{
得到
{
返回_hwnd;
}
}
}
}
@ StephenCleary的答案是正确的。虽然,我不得不做一点修改他的回答得到的行为我认为OP希望。
公共无效GoAsync()//不再异步作为Appication.Run它阻止
{
VAR所有者=新Win32Window(Process.GetCurrentProcess()MainWindowHandle);
_progressForm =新Form1的(); VAR进度=新的进展和LT; INT>(价值=> _progressForm.UpdateProgress(值)); _progressForm.Activated + =异步(发件人,参数)=>
{
等待围棋(进度);
_progressForm.Close();
}; Application.Run(_progressForm);
}
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.
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.
Questions: Can my code be fixed fairly easily? If so, how? Or, should I be using a different approach (e.g. BackgroundWorker)?
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'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进度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!