我有一个C#WinForms应用程序。在启动主UI表单之前显示DevExpress XtraMessageBox时,会在static void Main()方法中抛出此异常。下面是代码(简化):
static void Main(string[] args)
{
// Display Splash Screen.
SplashForm.Start();
if (!CheckLicense())
XtraMessageBox.Show(null, "Not Licensed!", "License Check",
MessageBoxButtons.OK, MessageBoxIcon.Information);
using (MainForm form = new MainForm())
{
SplashForm.Stop();
if (form != null)
Application.Run(form);
}
}
虽然它是一个DevExpress控件,但实际上会在调用时抛出异常:
System.Drawing.Graphics.get_PageUnit()
不会一直抛出异常。它可以在特定的机器上重现,但是一旦我在异常之前添加MicroSoft MessageBox.Show()以显示调试信息,那么我就不再获得异常。这是堆栈跟踪:
Object is currently in use elsewhere.
at System.Drawing.Graphics.get_PageUnit()
at DevExpress.Utils.Text.FontsCache.GetFontCacheByFont(Graphics graphics, Font font)
at DevExpress.Utils.Text.FontsCache.GetStringSize(Graphics graphics, String text, Font font, StringFormat stringFormat, Int32 maxWidth)
at DevExpress.Utils.Text.TextUtils.GetStringSize(Graphics g, String text, Font font, StringFormat stringFormat, Int32 maxWidth)
at DevExpress.Utils.Paint.XPaintMixed.CalcTextSize(Graphics g, String s, Font font, StringFormat strFormat, Int32 maxWidth)
at DevExpress.Utils.AppearanceObject.CalcTextSize(Graphics g, StringFormat sf, String s, Int32 width)
at DevExpress.Utils.AppearanceObject.CalcTextSize(Graphics g, String s, Int32 width)
at DevExpress.XtraEditors.Drawing.EditorButtonPainter.CalcCaptionSize(EditorButtonObjectInfoArgs e)
at DevExpress.XtraEditors.Drawing.EditorButtonPainter.CalcObjectMinBounds(ObjectInfoArgs e)
at DevExpress.XtraEditors.Drawing.SkinEditorButtonPainter.CalcObjectMinBounds(ObjectInfoArgs e)
at DevExpress.XtraEditors.ViewInfo.BaseButtonViewInfo.CalcBestFit(Graphics g)
at DevExpress.XtraEditors.BaseControl.CalcBestSize()
at DevExpress.XtraEditors.XtraMessageBoxForm.CreateButtons()
at DevExpress.XtraEditors.XtraMessageBoxForm.ShowMessageBoxDialog()
at DevExpress.XtraEditors.XtraMessageBoxForm.ShowMessageBoxDialog(XtraMessageBoxArgs message)
at DevExpress.XtraEditors.XtraMessageBox.Show(UserLookAndFeel lookAndFeel, IWin32Window owner, String text, String caption, DialogResult[] buttons, Icon icon, Int32 defaultButton, MessageBoxIcon messageBeepSound)
at DevExpress.XtraEditors.XtraMessageBox.Show(IWin32Window owner, String text, String caption, DialogResult[] buttons, Icon icon, Int32 defaultButton, MessageBoxIcon messageBeepSound)
at DevExpress.XtraEditors.XtraMessageBox.Show(IWin32Window owner, String text, String caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
at DevExpress.XtraEditors.XtraMessageBox.Show(IWin32Window owner, String text, String caption, MessageBoxButtons buttons, MessageBoxIcon icon)
at Test.Program.Main(String[] args)
更新 我通过确保在执行任何UI工作之前执行Application.Run()来解决它。以这种方式启动消息循环/泵。我现在让Application.Run()启动了splash表单,它是轻量级和快速的。在启动表单中,然后我实例化主表单,激活它并隐藏启动表单。
答案 0 :(得分:1)
据我了解,Application.Run()
需要在显示任何表单之前专门调用,因为它启动窗口消息循环/泵并基本上为UI生成一个单独的线程。
如果您不这样做,表单将无法处理消息或绘画。
我的建议是,加载主窗体并让主窗体调用启动屏幕,然后再执行任何正常的FormLoad
内容。如果许可失败,您可以从Application.Exit()
拨打return
和FormLoad
,从而在用户可以使用之前关闭您的应用。
修改:请注意,在FormLoad
退出之后,主窗体才会显示,因此您无需担心在初始屏幕显示时隐藏主窗体。< / p>
编辑2 :我使用ApplicationContext
找到了值得的东西。您可以在主上下文中切换出哪个表单,这样您就可以在初始应用程序上下文中加载启动画面,然后在加载后将其交换出来。试试这个:
public class MyApplicationContext : ApplicationContext {
SplashForm splashForm;
MainForm mainForm;
public MyApplicationContext() {
splashForm = new SplashForm();
base.MainForm = splashForm;
}
public void RunApplication() {
// This will show the splash screen
ThreadPool.QueueUserWorkItem(new WaitCallback(MessageLoopThread));
// This will perform any miscellaneous loading functions
splashForm.PerformLoadingFunctions();
if (!CheckLicensing()) {
ShowErrorMessage();
Application.Exit();
return;
}
// Now load the main form
mainForm = new MainForm();
// We're done loading! Swap out our objects
base.MainForm = mainForm;
// Close our splash screen
splashForm.Close();
splashForm.Dispose();
splashForm = null;
}
private void MessageLoopThread(object o) {
Application.Run(this);
}
}
然后你可以在你的主要电话中打电话:
static void Main() {
MyApplicationContext applicationContext = new MyApplicationContext();
applicationContext.RunApplication();
}
我没有对此进行过测试,但理论上它应该可行。
编辑3:我意识到这里可能存在一些线程安全问题,您可能还需要解决。查看CodeProject article。它比我在这里做得更好。