来源:http://www.cnblogs.com/rainbowzc/archive/2010/09/29/1838788.html
由于多线程可能导致对控件访问的不一致,导致出现问题。C#中默认是要线程安全的,即在访问控件时需要首先判断是否跨线程,如果是跨线程的直接访问,在运行时会抛出异常。
解决办法有两个:
1、不进行线程安全的检查
2、通过委托的方式,在控件的线程上执行
常用写法:(不安全)
private void WriteToolStripMsg(string msg, Color color)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new MethodInvoker(delegate()
{
toolStripMsg.Text = msg;
toolStripMsg.ForeColor = color;
}));
}
else
{
toolStripMsg.Text = msg;
toolStripMsg.ForeColor = color;
}
}
private void btnLogin_Click(object sender, EventArgs e)
{
string userName = this.txtUserName.Text.Trim();
string pwd = this.txtPwd.Text.Trim();
if (userName.IsNullOrEmpty())
{
WriteToolStripMsg("请输入登录名...", Color.Red);
this.txtUserName.Focus();
return;
}
if (pwd.IsNullOrEmpty())
{
WriteToolStripMsg("请输入密码...", Color.Red);
this.txtPwd.Focus();
return;
}
if (userName.IsNotEmpty() && pwd.IsNotEmpty())
{
WriteToolStripMsg("系统正在登陆中...", Color.Blue);
this.btnLogin.BtnEnabled = false;
string msg = string.Empty;
Thread t = new Thread(() =>
{
//判断用户登录是否成功。
string restulMsg = string.Empty;
restulMsg = DataCenterService.Instance.Login(userName, pwd);
if (restulMsg.IsNullOrEmpty())
{
SysUser.CurrUserEntity = DataCenterService.Instance.GetInfoForName(userName);
this.DialogResult = DialogResult.OK;
}
else
{
WriteToolStripMsg(restulMsg, Color.Red);
this.BeginInvoke(new MethodInvoker(delegate()
{
this.btnLogin.BtnEnabled = true;
}));
}
});
t.IsBackground = true;
t.Start();
}
}
上述写法并不是最安全的,存在一定的问题。
推荐写法:
delegate void UpdateShowInfoDelegate(System.Windows.Forms.TextBox txtInfo, string Info);
/// <summary>
/// 显示信息
/// </summary>
/// <param name="txtInfo"></param>
/// <param name="Info"></param>
public void ShowInfo(System.Windows.Forms.TextBox txtInfo, string Info)
{
if (this.InvokeRequired)
{
//this.BeginInvoke(new MethodInvoker(delegate()
//{
// txtInfo.AppendText(Info);
// txtInfo.AppendText(Environment.NewLine + "\r\n");
// txtInfo.ScrollToCaret();
//}));
Invoke(new UpdateShowInfoDelegate(ShowInfo), txtInfo,Info);
return;
}
else
{
txtInfo.AppendText(Info);
txtInfo.AppendText(Environment.NewLine + "\r\n");
txtInfo.ScrollToCaret();
}
}
How to update the GUI from another thread in C#?
本文转载:http://stackoverflow.com/questions/661561/how-to-update-the-gui-from-another-thread-in-c
在CodeProject上看一个跨线程更新的方法,备忘一下。 如果在应用中存在较多简单的跨线程操作,下面的方法可能比较实用:
public static class ExtensionMethod
{
/// <summary>
/// 有返回值的扩展方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="isi"></param>
/// <param name="call"></param>
/// <returns></returns>
public static TResult SafeInvoke<T, TResult>(this T isi, Func<T, TResult> call) where T : ISynchronizeInvoke
{
if (isi.InvokeRequired) {
IAsyncResult result = isi.BeginInvoke(call, new object[] { isi });
object endResult = isi.EndInvoke(result); return (TResult)endResult;
}
else
return call(isi);
}
/// <summary>
/// 没有返回值的扩展方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="isi"></param>
/// <param name="call"></param>
public static void SafeInvoke<T>(this T isi, Action<T> call) where T : ISynchronizeInvoke
{
if (isi.InvokeRequired) isi.BeginInvoke(call, new object[] { isi });
else
call(isi);
}
}
然后在使用时就可以使用匿名委托很方便的操作:
lblProcent.SafeInvoke(d => d.Text = textForLabel);
progressBar1.SafeInvoke(d => d.Value = i);
string
labelText = lblProcent.SafeInvoke(d => d.Text);
静态的扩展类方法使用泛型模板扩展像所有可继承 ISynchronizeInvoke 接口的控件,几乎适用于常见的所有控件呦 (来自 CodeProject 为所有类型的更新创建异步委托)
原始地址:http://www.codeproject.com/Articles/52752/Updating-Your-Form-from-Another-Thread-without-Cre