我只是想更新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
),一切都运行正常,但显然进度条根本没有更新。
答案 0 :(得分: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; } ) );
这将在异步线程上执行操作。
答案 1 :(得分:0)
我编辑你的代码。如果你想要屏幕不要冻结,可能很简单的方法是使用后台工作程序来执行操作。
当您使用后台工作程序时,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 ");
}
}