背景
根据我收到的宝贵建议here我现在已将所有数据库密集型代码移至后台工作者,特别是直接调用数据库。该代码在backgroundworker的DoWork事件期间执行。如果在DoWork事件期间返回DataTable,我将该DataTable设置为类范围的变量。这样做是为了避免每次运行此代码时都必须调用需要DataTable的控件。
在执行该代码时,我有一个在主UI线程中更新的标签,让用户知道正在发生的事情。为了更新标签,我使用一个计时器,这样每隔750毫秒一个“。”被附加到标签的字符串。
我注意到的第一件事是后台工作者的RunWorkerCompleted事件没有触发。为了解决这个问题,我在每次打电话给后台工作人员之前做了Application.DoEvents();
。它很难看,但它引发了事件。如果有人有办法解决这个问题,我全都听见了。
问题
任何人都可以解释正在发生的事情/提出如何改进的建议吗?
代码
我无法发布所有涉及的代码,但这里有一些相关的东西:
namespace Test
{
public partial class frmMain : Form
{
public static Boolean bStatus = false;
static Boolean bTimer = false;
System.Timers.Timer MyTimer = new System.Timers.Timer();
public frmMain()
{
InitializeComponent();
MyTimer.Elapsed += new System.Timers.ElapsedEventHandler(MyTimer_Elapsed);
MyTimer.Interval = 750; // Every 3/4 of a second
ExampleTrigger();
}
/// <Insert>Lots of unshown code here</Insert>
private void ExampleTrigger()
{
// This is used to simulate an event that would require the backgroundworker
Application.DoEvents();
bgw.RunWorkerAsync(0);
WaitText("Example - 1");
}
private static void MyTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
bTimer = true;
}
// Update status text
private void WaitText(string txt)
{
MyTimer.Enabled = true;
lblStatus.Text = txt;
bStatus = false;
while (!bStatus)
{
if (bTimer)
{
txt = txt + ".";
lblStatus.Text = txt;
lblStatus.Update();
bTimer = false;
}
}
MyTimer.Enabled = false;
}
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
int iSelect = (int)e.Argument;
switch (iSelect)
{
case 0:
// Hit the database
break;
/// <Insert>Other cases here</Insert>
default:
// Do something magical!
break;
}
}
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bStatus = true;
lblStatus.Text = "Ready!"; // This is where the exception occurs!
}
}
}
答案 0 :(得分:0)
永远不要像在UI线程中那样运行while()
循环
您将冻结UI,直到循环终止;这违背了目的。
此外,System.Timers.Timer
不会在UI线程中运行回调
请改用WinForms Timer。
切换到WinForms计时器后,您只需附加到计时器回调中的标签,并在操作完成时禁用计时器。