项目开发总结:解决多线程窗体与主风格不一致问题
这个星期干的事还比较多的,写了些文档,以前做的系统很多不合理的地方修改下更人性化和新增一些功能,忙是忙,不过算过得挺充实的,特别是解决了一些问题后的激情。解决问题后就做个总结吧,以后或许经常遇到类似问题的。
经常遇到这样的情景:在处理一个耗时操作时开启一个线程来处理,在后台线程处理数据或逻辑后给用户一个提示,常见的MessagBox之类的,Control.BeginInvoke这里就免谈了,都懂的,偷下懒,直接在所有窗体加载之前(可在Main函数里面)加上System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls = false; 静态属性,无论有多少个窗体实例化都有效,你懂的,这样就能实现非UI线程访问UI线程创建的控件不报异常。
登录窗体,可能数据库连接字符串与实际的网络环境不一样,就要判断连接,或者登录要花比较长时间,这里就要用到多线程:
//开启后台线程处理可能的耗时操作---登录与数据库交互及相关逻辑
this.threadLogin = new Thread(new ThreadStart(LoginProcess)) { IsBackground = true };
this.threadLogin.Start();
this.marqueeProgressBarControl1.Visible = true;
this.marqueeProgressBarControl1.Properties.Stopped = false;
this.txtUserName.Enabled = false;
this.txtPwd.Enabled = false;
this.btnConfig.Enabled = false;
this.btnLogin.Enabled = false;
在登录处理的线程里面:
结果运行的MessageBox风格给换了,不是上面的Office 2007 Blue风格了:
分析:Main()函数在执行Aplication.Run()之前已经完成线程窗体主题注册和初始化,这些只对主线程有效,而对其他线程无效,因此,对比Main函数写一个公共函数先注册主题皮肤和设置主题皮肤,在执行MessgeBox:
/// <summary>
/// 在多线程中弹出消息 解决消息窗体与主窗体theme不一致的问题
/// </summary>
/// <param name="owner"></param>
/// <param name="message"></param>
public static void ShowMessage(IWin32Window owner,string message)
{
DevExpress.UserSkins.BonusSkins.Register();
DevExpress.UserSkins.OfficeSkins.Register();
DevExpress.Skins.SkinManager.EnableFormSkins();
DevExpress.LookAndFeel.UserLookAndFeel.Default.SkinName = CommonLibrary.PublicFunction.gettheme(); //MainForm.gspLookAndFeel.LookAndFeel.SkinName;
XtraMessageBox.Show(owner,message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
然后在非主线程里面调用:
运行结果:
OK,窗体主题一致,搞定!
分析本质:执行更新或操作控件的行为发生在哪个线程上,用System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls = false不用Control.BeginInvoke时更新或操作控件的行为发生在非UI线程,故需在该线程里面注册和设置主题;若使用Control.BeginInvoke,MSDN的解释是:在创建控件的基础句柄所在线程上异步执行指定委托。则更新或操作控件的行为发生在主UI线程——即创建控件的线程,自然和原窗体主题一致。