【问题标题】:Updating UI from Parallel.ForEach从 Parallel.ForEach 更新 UI
【发布时间】:2018-04-22 10:05:41
【问题描述】:

我只是想更新Parallel.ForEach 中的进度条,应用程序似乎冻结了。

尽管我已经按照其他帖子的建议尝试使用Invoke 解决方案,但我仍然遇到问题。

这是我的代码的简化版本:

public partial class Form1 : Form
{
    event EventHandler ReportProgress;

    class ProgressEvent : EventArgs
    {
        public int Total { get; set; }
        public int Current { get; set; }
    }

    public Form1()
    {
        InitializeComponent();
        ReportProgress += Form1_ReportProgress;
    }

    private void Form1_ReportProgress( object sender, EventArgs e )
    {
        var progress = e as ProgressEvent;
        if ( InvokeRequired )
        {
            this.Invoke( new Action( () => { progressBar.Maximum = progress.Total; progressBar.Value = progress.Current; } ) );
        }
    }

    private void buttonStart_Click( object sender, EventArgs e )
    {
        // Create a list with seed to be used later
        List<int> values = new List<int>() { };
        values.AddRange( Enumerable.Range( 1, 15 ) );

        var total = values.Count();
        var current = 0;

        Parallel.ForEach( values, v =>
        {
            Interlocked.Increment( ref current );

            var r = new Random( v );
            // Just sleep a little
            var sleep = r.Next( 10, 1000 );
            Thread.Sleep( sleep );

            // Update the progress bar
            ReportProgress( null, new ProgressEvent() { Current = current, Total = total } );
        }
        );

        MessageBox.Show( "Done " );
    }
}

应用程序似乎挂起并且没有显示消息框,而如果我删除事件生成 (ReportProgress) 一切正常,但显然进度条根本没有更新。

【问题讨论】:

标签: c# winforms parallel.foreach


【解决方案1】:

你可以改变:

this.Invoke( new Action( () => { progressBar.Maximum = progress.Total; progressBar.Value = progress.Current; } ) );

到:

this.BeginInvoke( new Action( () => { progressBar.Maximum = progress.Total; progressBar.Value = progress.Current; } ) );

这将在异步线程上执行操作。

【讨论】:

    【解决方案2】:

    我编辑你的代码。如果您想屏幕不冻结,可能更简单的方法是使用后台工作人员执行操作。

    当您使用后台工作时,UI线程不会被阻塞。因此,用户仍然可以与UI交互。

    public partial class Form1 : Form
    {
        event EventHandler ReportProgress;
    
        class ProgressEvent : EventArgs
        {
            public int Total { get; set; }
            public int Current { get; set; }
        }
    
        public Form1()
        {
            InitializeComponent();
            ReportProgress += Form1_ReportProgress;
        }
    
        private void Form1_ReportProgress(object sender, EventArgs e)
        {
            var progress = e as ProgressEvent;
            this.Invoke(new Action(() =>
                                   {
                                       progressBar.Maximum = progress.Total;
                                       progressBar.Value = progress.Current;
                                   }));
        }
    
        private void button1_Click(object sender, EventArgs e)
        {
            // Collect data from UI, I use list for example
            List<int> values = new List<int>() { };
            values.AddRange(Enumerable.Range(1, 100));
    
            BackgroundWorker backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += BackgroundWorkerOnDoWork;
            backgroundWorker.RunWorkerAsync(values);
        }
    
        private void BackgroundWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
        {
            var values = (IEnumerable<int>) doWorkEventArgs.Argument; // the 'argument' parameter resurfaces here
    
            var total = values.Count();
            var current = 0;
    
            Parallel.ForEach(values, v =>
                                     {
                                         Interlocked.Increment(ref current);
    
                                         var r = new Random(v);
                                         // Just sleep a little
                                         var sleep = r.Next(10, 1000);
                                         Thread.Sleep(sleep);
    
                                         // Update the progress bar
                                         ReportProgress(null, new ProgressEvent() {Current = current, Total = total});
                                     }
                            );
    
            MessageBox.Show("Done ");
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-04
      相关资源
      最近更新 更多