我有两个按钮启动和停止。在开始按钮的单击时,我想打一个表并循环记录,显示记录在循环中的时间差(所用时间)。
然而,当单击开始按钮时,由于记录数量很高,我无法单击“停止”按钮,我试图单击开始按钮,独立运行该过程,例如,如果处理了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.
}
}
答案 0 :(得分:1)
您可以使用BackgroundWorker的好处。
您可以直接跳到代码,但只是为了获取一般信息,BackgroundWorker以友好的方式包装了后台线程的管理。 您需要使用的主要事件是:
RunWorkerAsync
”方法触发的。 RunWorkerAsync
”的线程上触发它,通常是您的GUI线程。它通过调用“workerInstance.ReportProgress()
”来触发,通常来自您的实际工作职能。RunWorkerAsync
”的线程上触发,通常是您的GUI线程。它在DoWork事件处理程序返回时触发。这是在作业完成后所需的操作。我认为你有两种选择:
如果您可以过早退出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;
}
}
}
如果无法过早退出LoadResults函数: (基于Robs answer)
/// <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);
}
答案 1 :(得分: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对象随着长期运行的任务的运行,你的用户界面。
在任务之前还会创建一个Stopwatch对象来记录任务运行的时间。
另请注意,当前记录会保留,以便在您停止后恢复时,它会从中断处继续。