如何在进度条完成时触发事件
本文关键字:完成时 事件 | 更新日期: 2023-09-27 18:09:02
我创建了一个Windows窗体程序,它可以分解文件并将其组件发送到服务器。这些文件很大,所以我创建了一个progressBar,这样用户就不会认为它在事务发生时冻结了。我想做的是有一些机制,将主动触发只有当所有线程完成而不阻塞UI线程(再次,所以平民不会认为它冻结)。我能想到的最好的办法是一种被动的"等到事情发生",但我觉得必须有更好的方法来做到这一点。我尝试过创建事件或回调,但老实说,我比开始时更困惑。下面是我现在如何做这件事的一个例子:
public partial class Program : Form
{
private readonly OpenFileDialog _ofd = new OpenFileDialog();
public delegate void BarDelegate();
private string _path;
private void button1_Click(object sender, EventArgs e)
{
if (_ofd.ShowDialog() != DialogResult.OK) return;
textBox1.Text = _ofd.SafeFileName;
_path = _ofd.FileName;
}
private void button2_Click(object sender, EventArgs e)
{
var allLinesFromFile = File.ReadAllLines(_path);
progressBar1.Minimum = 0;
progressBar1.Maximum = allLinesFromFile.Length;
Task.Factory.StartNew(() => Parallel.ForEach(allLinesFromFile, DoSomething));
while (progressBar1.Value < progressBar1.Maximum) //there has to be a better way to do this...
{
MessageBox.Show("Please wait.", "Record Poster", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
}
//some processes here which should only take place after all threads are complete.
var postingComplete = MessageBox.Show("The posting is complete!", "Record Poster", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
if (postingComplete == DialogResult.OK) Environment.Exit(0);
}
private void DoSomething(string record)
{
//some string manipulation and server transactions here
BeginInvoke(new BarDelegate(() => progressBar1.Increment(1)));
}
}
尝试使用微软的响应式框架(NuGet "System.Reactive.Windows.Forms")。然后你的代码变成:
private void button2_Click(object sender, EventArgs e)
{
var allLinesFromFile = File.ReadAllLines(_path);
progressBar1.Minimum = 0;
progressBar1.Maximum = allLinesFromFile.Length;
IDisposable subscription =
allLinesFromFile
.ToObservable()
.SelectMany(f => Observable.Start(() => DoSomething(f)))
.ObserveOn(this)
.Do(x => progressBar1.Value += 1)
.Subscribe(x => { }, () =>
{
var postingComplete = MessageBox.Show("The posting is complete!", "Record Poster", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
if (postingComplete == DialogResult.OK)
{
Application.Exit();
}
});
}
private void DoSomething(string record)
{
System.Threading.Thread.Sleep(5);
}
如果你想早点停止,那就打电话给subscription.Dispose()
。
你应该使用BackGroundWorker类,参见:如何使用BackGroundWorker ?
和使用BackGroundWorker.RunWorkerComplete
时,线程已经完成
后台worker:
**Backgroundworker (System.ComponentModel)**
BackgroundWorker loader = new BackgroundWorker();
loader.DoWork += load_Specials_BW_Thread;
loader.WorkerReportsProgress = true;
loader.ProgressChanged += load_Special_Feeds_Progress_Changed;
private void load_Specials_BW_Thread(object sender, DoWorkEventArgs e)
{
int pctComplete = (int)Math.Floor(ptComplete * 100);//recs done / total recs
(sender as BackgroundWorker).ReportProgress(pctComplete);
}
祝你好运!