Scenario:
1、程式启动时,计算器在刷新时间。
2、点击“Go”,按钮无效状态,计算停止。
3、5秒后按钮恢复状态,计算重新启动。
4、2-3之间UI不能出现阻塞,即是要用多线程。
程序:
1、定义界面接口IForm
public interface IForm
{
/// <summary>
/// 启动Button
/// </summary>
void EnableButton();
/// <summary>
/// 禁用Button
/// </summary>
void DisableButton();
/// <summary>
/// 停止计时器
/// </summary>
void StopTimer();
/// <summary>
/// 启用计时器
/// </summary>
void RecoverTimer();
}
2、异步运行程式
public class Test
{
/// <summary>
/// 执行
/// </summary>
/// <param name="form"></param>
static void AsyncMethod(IForm form)
{
//禁用状态
form.DisableButton();
form.StopTimer();
//停止5秒
Thread.Sleep(5000);
}
public static void Do(IForm form)
{
MyProcess myProcess = new MyProcess(AsyncMethod);
AsyncCallback callback = new AsyncCallback(MyCallback);
//异步调用
myProcess.BeginInvoke(form, callback, form);
}
static void MyCallback(IAsyncResult ar)
{
AsyncResult res = (AsyncResult)ar;
MyProcess del = (MyProcess)res.AsyncDelegate;
del.EndInvoke(ar);
IForm form = (IForm)res.AsyncState;
//恢复启用
form.EnableButton();
form.RecoverTimer();
}
}
3、界面代码
public partial class Form1 : Form, IForm
{
public Form1()
{
InitializeComponent();
}
private void btn_Click(object sender, EventArgs e)
{
Test.Do(this);
}
private void timer1_Tick(object sender, EventArgs e)
{
this.lblCurrentDate.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
public void EnableButton()
{
this.btn.Enabled = true;
}
public void DisableButton()
{
this.btn.Enabled = false;
}
public void StopTimer()
{
this.timer1.Stop();
}
public void RecoverTimer()
{
this.timer1.Start();
}
}
如此调用,常理来说应该正确,但.net会抛出异常。
解决办法
根据“排错提示”,查看MSDN的“
如何:对 Windows 窗体控件进行线程安全调用”即可得到答案。
如下修改界面代码即可
public void EnableButton()
{
//使用控件的InvokeRequired判断执行Invoke
if (this.btn.InvokeRequired)
{
this.Invoke(new AscyUpdateControl(EnableButton));
}
else
{
this.btn.Enabled = true;
}
}
public void DisableButton()
{
if (this.btn.InvokeRequired)
{
this.Invoke(new AscyUpdateControl(DisableButton));
}
else
{
this.btn.Enabled = false;
}
}
public void StopTimer()
{
//如没有InvokeRequired属性,简写如下代码即可
this.Invoke(new AscyUpdateControl(delegate
{
this.timer1.Stop();
}));
}
public void RecoverTimer()
{
this.Invoke(new AscyUpdateControl(delegate
{
this.timer1.Start();
}));
}
代码