Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用WinForms ProgressBar异步/等待_C#_Multithreading_Winforms_Asynchronous_Async Await - Fatal编程技术网

C# 使用WinForms ProgressBar异步/等待

C# 使用WinForms ProgressBar异步/等待,c#,multithreading,winforms,asynchronous,async-await,C#,Multithreading,Winforms,Asynchronous,Async Await,我曾经在BackgroundWorker中使用过这种方法,但是我想使用.NET4.5中新的异步/等待方法。我可能找错人了。请告知 目标:创建一个组件,该组件将执行一些长期运行的工作,并在工作时显示一个带有进度条的模式表单。组件在执行长时间运行的工作时,将获得窗口的句柄以阻止交互 状态:请参阅下面的代码。在我尝试与窗户互动之前,我一直认为自己做得很好。如果我不去碰东西(即不要碰!),一切都会“完美地”运行,但如果我只点击其中一个窗口,程序就会在长时间运行的工作结束后挂起。实际交互(拖动)被忽略,就

我曾经在BackgroundWorker中使用过这种方法,但是我想使用.NET4.5中新的异步/等待方法。我可能找错人了。请告知

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

状态:请参阅下面的代码。在我尝试与窗户互动之前,我一直认为自己做得很好。如果我不去碰东西(即不要碰!),一切都会“完美地”运行,但如果我只点击其中一个窗口,程序就会在长时间运行的工作结束后挂起。实际交互(拖动)被忽略,就好像UI线程被阻塞一样

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

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

使用系统;
使用系统诊断;
使用系统线程;
使用System.Threading.Tasks;
使用System.Windows.Forms;
命名空间控制台应用程序1
{
班级计划
{
静态void Main(字符串[]参数)
{
Console.WriteLine(“启动…”);
var mgr=新经理();
经理GoAsync();
控制台写入线(“…结束”);
Console.ReadKey();
}
}
班级经理
{
私有静态表单1u progressForm;
公共异步void GoAsync()
{
var owner=new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
_progressForm=新Form1();
_progressForm.Show(所有者);
等待出发();
_progressForm.Hide();
}
专用异步任务Go()
{
var job=new LongJob();
job.OnProgress+=作业进度;
job.Spin();
返回true;
}
无效作业进度(整数百分比)
{
_progressForm.UpdateProgress(百分比);
}
}
班长
{
公共活动不断进展;
已进行的公共代表无效(整数百分比);
公共空间
{

对于(var i=1;i,
async
await
关键字并不意味着“在后台线程上运行”。我有一个描述它们含义的示例。您必须明确地将CPU绑定的操作放在后台线程上,例如,
Task.run

此外,本文档还介绍了使用
async
code的常用方法,例如进度报告

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);
      }
    }
  }
}
类管理器
{
私有静态表单1u progressForm;
公共异步任务GoAsync()
{
var owner=new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
_progressForm=新Form1();
_progressForm.Show(所有者);
var progress=newprogress(值=>_progressForm.UpdateProgress(值));
等待进展;
_progressForm.Hide();
}
私人任务Go(IProgress进度)
{
返回任务。运行(()=>
{
var job=new LongJob();
工作。旋转(进度);
返回true;
});
}
}
班长
{
公共空间旋转(IProgress进度)
{

对于(var i=1;i@StephenCleary的答案是正确的。不过,我不得不对他的答案做一些修改,以获得我认为OP想要的行为

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);
}
public void GoAsync()//不再异步,因为它会阻塞应用程序。运行
{
var owner=new Win32Window(Process.GetCurrentProcess().MainWindowHandle);
_progressForm=新Form1();
var progress=newprogress(值=>_progressForm.UpdateProgress(值));
_progressForm.Activated+=async(发送方,参数)=>
{
等待进展;
_progressForm.Close();
};
应用程序运行(_progressForm);
}
专用异步无效按钮1\u单击(对象发送方,事件参数e)
{
IProgress progress=new progress(值=>{progressBar1.value=value;});
等待任务。运行(()=>
{

对于(int i=0;i您的更改没有产生预期的结果。由于OP是在
控制台
应用程序中运行的,因此没有
同步上下文
。我认为需要引入它才能使
进度
正常工作?Windows窗体组件在运行时将建立一个
WinFormsSynchronizationContext
重新创建,
Progress
不需要
SynchronizationContext
(尽管它使用SynchronizationContext会更好)。我在传递给
Progress
的委托中放置了一个断点-它从未被命中-UI只是挂起,尽管作业正在旋转。我认为
Application.Run()
需要建立
SynchronizationContext
-是否需要
\u progressForm.Show
建立一个?我不确定。我相信有一个
SynchronizationContext
,但没有主循环。
main
必须调用
应用程序。运行
显示对话框
,或者类似的东西。是的,你是对的。
SynchronizationContext
存在-但是没有循环来处理发布/发送给它的内容。因此我的断点不会命中。谢谢。如果Go(progress)抛出异常,则永远不会调用\u progressForm.Close()->模式对话框将永远挂起,最好将“\u progressForm.Activated”更改为“\u progressForm.Showed”因为_progressForm可能在其生命周期内被激活多次..->Go(progress)将被调用多次。。
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);
}
private async void button1_Click(object sender, EventArgs e)
{
    IProgress<int> progress = new Progress<int>(value => { progressBar1.Value = value; });
    await Task.Run(() =>
    {
        for (int i = 0; i <= 100; i++)
            progress.Report(i);
    });
}