1

我有两个按钮启动和停止。单击开始按钮时,我想点击表格并循环记录,显示记录在循环中时的时间差(所用时间)。

但是,当单击开始按钮时,由于记录数很高,我无法单击“停止”按钮,我试图单击开始按钮,独立运行该过程,例如,如果处理了 5000 条记录,当我单击停止按钮,我想显示这 5000 条记录所花费的时间,再次单击开始时,继续记录它离开的地方。

我如何独立处理两个事件?任何想法都会非常有帮助。在此先感谢。

private void startQueries()
{


thread=

new Thread(this.LoadResults);

thread.IsBackground =true;

thread.Start();

}

private void LoadResults()
{
 //Method that runs a select query - fetches 1000s of records
 Timespan startTime = <<Record the start time>>;

 //Loop thro' all the 1000s of records;

Timespan stopTime=<<Record the stop time>>;

//Display the difference between start and stop time.

}

    private void btnStart_Click(object sender, EventArgs e)
    {

    if(thread!=null)
    {
    if (thread.ThreadState == ThreadState.Running)
    {
    //do nothing
    }
    else if (thread.ThreadState == ThreadState.Suspended)
    {
    startQueries();
    }

    }

private void btnStop_Click(object sender, EventArgs e)
{
  //Stop the running thread

 // Need to display the time between the thread start and stop.
}
}
4

2 回答 2

1

您可以使用BackgroundWorker的好处。

您可以直接跳到代码,但只是为了一般信息,BackgroundWorker 以友好的方式包装了后台线程的管理。您需要使用的主要事件是:

  1. DoWork - 在另一个线程上触发(即异步),这适用于您繁重、缓慢的工作。它是通过调用“ RunWorkerAsync”方法触发的。
  2. ProgressChanged - 它在RunWorkerAsync调用“”的线程上触发,通常是您的 GUI 线程。它是通过调用“ workerInstance.ReportProgress()”触发的,通常来自您的实际工作功能。
  3. RunWorkerCompleted - 在您调用“”的线程上触发RunWorkerAsync,通常是您的 GUI 线程。它在 DoWork 事件处理程序返回时触发。这是作业完成后所需的操作。

在我看来,您有两种选择:

  1. 如果您可以过早退出 LoadResults 函数:

    /// <summary>
    /// The BackgroundWorker to handle you async work
    /// </summary>
    BackgroundWorker bw = new BackgroundWorker
    {
        WorkerReportsProgress = true,
        WorkerSupportsCancellation = true
    };
    
    /// <summary>
    /// Handles the Click event of the btnStart control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
    private void btnStart_Click(object sender, EventArgs e)
    {
        if (bw.IsBusy)
        {
            return;
        }
    
        System.Diagnostics.Stopwatch sWatch = new System.Diagnostics.Stopwatch();
        bw.DoWork += (bwSender, bwArg) =>
        {
            //what happens here must not touch the form
            //as it's in a different thread        
            sWatch.Start();
            this.LoadResults();
        };
    
        bw.ProgressChanged += (bwSender, bwArg) =>
        {
            //update progress bars here
        };
    
        bw.RunWorkerCompleted += (bwSender, bwArg) =>
        {
            //now you're back in the UI thread you can update the form
            //remember to dispose of bw now               
    
            sWatch.Stop();
            MessageBox.Show(String.Format("Thread ran for {0} milliseconds",sWatch.ElapsedMilliseconds));
            //work is done, no need for the stop button now...
            this.btnStop.Enabled = false;
            bw.Dispose();
        };
    
        //lets allow the user to click stop
        this.btnStop.Enabled = true;
        //Starts the actual work - triggerrs the "DoWork" event
        bw.RunWorkerAsync();
    
    
    }
    
    /// <summary>
    /// Handles the Click event of the btnStop control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
    private void btnStop_Click(object sender, EventArgs e)
    {
        //Stop the running thread
        this.bw.CancelAsync();
        // Need to display the time between the thread start and stop.
    }
    
    private void LoadResults()
    {
        //When you check if cancelation is pending:
        for (int i = 0; i < 5; i++)
        {
            //Simulating some job time
            Thread.Sleep(1000);
    
            if (bw.CancellationPending)
            {
                return;
            }
    
        }
    
    
    }
    
  2. 如果您不能过早退出 LoadResults 函数:(基于 Rob回答

        /// <summary>
        /// The BackgroundWorker to handle you async work
        /// </summary>
        BackgroundWorker bw = new BackgroundWorker
        {
            WorkerReportsProgress = true,
            WorkerSupportsCancellation = true
        };
    
        /// <summary>
        /// Handles the Click event of the btnStart control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            if (bw.IsBusy)
            {
                return;
            }
    
            System.Diagnostics.Stopwatch sWatch = new System.Diagnostics.Stopwatch();
            bw.DoWork += (bwSender, bwArg) =>
            {
                //what happens here must not touch the form
                //as it's in a different thread        
                sWatch.Start();
    
    
                var _child = new Thread(() =>
                {
                    this.LoadResults();
    
                });
                _child.Start();
                while (_child.IsAlive)
                {
                    if (bw.CancellationPending)
                    {
                        _child.Abort();
                        bwArg.Cancel = true;
                    }
                    Thread.SpinWait(1);
                }                
    
            };
    
            bw.ProgressChanged += (bwSender, bwArg) =>
            {
                //update progress bars here
            };
    
            bw.RunWorkerCompleted += (bwSender, bwArg) =>
            {
                //now you're back in the UI thread you can update the form
                //remember to dispose of bw now               
    
                sWatch.Stop();
                MessageBox.Show(String.Format("Thread ran for {0} milliseconds",sWatch.ElapsedMilliseconds));
                //work is done, no need for the stop button now...
                this.btnStop.Enabled = false;
                bw.Dispose();
            };
    
            //lets allow the user to click stop
            this.btnStop.Enabled = true;
            //Starts the actual work - triggerrs the "DoWork" event
            bw.RunWorkerAsync();
    
    
        }
    
        /// <summary>
        /// Handles the Click event of the btnStop control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btnStop_Click(object sender, EventArgs e)
        {
            //Stop the running thread
            this.bw.CancelAsync();
            // Need to display the time between the thread start and stop.
        }
    
        private void LoadResults()
        {
            //Simulation job time...
            Thread.Sleep(5000);
        } 
    
于 2013-07-09T05:04:58.507 回答
0

如果您使用的是 .NET 4.5 或更高版本,则可以使用更新的异步功能,它为您的代码提供干净、顺序的流程,即使它仍然是异步发生的。

public partial class Form1 : Form
{
    CancellationTokenSource _cancellationSource;
    int _currentRecord;
    int _maxRecord;

    public Form1()
    {
        InitializeComponent();
        _currentRecord = 0;
        _maxRecord = 5000;
    }

    private async void btnStart_Click(object sender, EventArgs e)
    {
        await StartQueriesAsync();
    }

    private async Task StartQueriesAsync()
    {
        _cancellationSource = new CancellationTokenSource();
        var sw = new Stopwatch();

        try
        {
            // for Progress<>, include the code that outputs progress to your UI
            var progress = new Progress<int>(x => lblResults.Text = x.ToString());
            sw.Start();
            // kick off an async task to process your records
            await Task.Run(() => LoadResults(_cancellationSource.Token, progress));
        }
        catch (OperationCanceledException)
        {
            // stop button was clicked
        }

        sw.Stop();
        lblResults.Text = string.Format(
            "Elapsed milliseconds: {0}", sw.ElapsedMilliseconds);
    }

    private void LoadResults(CancellationToken ct, IProgress<int> progress)
    {
        while(_currentRecord < _maxRecord)
        {
            // watch for the Stop button getting pressed
            if (ct.IsCancellationRequested)
            {
                ct.ThrowIfCancellationRequested();
            }

            // optionally call this to display current progress
            progress.Report(_currentRecord);

            // simulate the work here
            Thread.Sleep(500);

            _currentRecord++;
        }
    }

    private void btnStop_Click(object sender, EventArgs e)
    {
        _cancellationSource.Cancel();
    }
}

当您单击“开始”按钮时,任务将通过Task.Run 启动并传递一个CancellationToken以监视“停止”按钮以及一个Progress对象,该对象包含用于在长时间运行的任务运行时更新 UI 的代码。

在任务之前还会创建一个Stopwatch对象来记录任务运行的时间。

另请注意,当前记录会保留,以便在您停止后继续时,它将从中断的地方继续。

于 2013-07-09T14:08:00.677 回答