如何在进度条完成时触发事件

时间:2016-09-27 19:59:59

标签: c# multithreading events

我创建了一个Windows Forms程序,它可以分解文件并将其组件发送到服务器。这些文件很大,所以我创建了一个progressBar,这样用户就不会认为它在事务发生时就会冻结。我想要做的是有一些机制,只有当所有线程都完整而没有阻塞UI线程时才会主动触发(再次,因此plebs不会认为它被冻结)。我能想出的最好的是一种被动的"等到真的"但我觉得必须有更好的方法来做到这一点。我已经尝试过尝试创建一个事件或回调,但老实说,我刚刚比起初时更加困惑。这是我现在如何做的一个例子:

    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)));
        }
    }

3 个答案:

答案 0 :(得分:1)

尝试使用Microsoft的Reactive Framework(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()。我测试了这个,它对我来说很好。

答案 1 :(得分:0)

您应该使用BackGroundWorker类,请参阅:How to use a BackgroundWorker?

在线程完成时使用BackGroundWorker.RunWorkerComplete

答案 2 :(得分:-1)

后台工作人员:

 **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);
    }
祝你好运!