0

C#WinFormsアプリケーションがあります。この例外は、メインUIフォームを起動する前にDevExpress XtraMessageBoxが表示されたときに、静的な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()がスプラッシュフォームを起動します。これは軽量で高速です。次に、スプ​​ラッシュフォーム内からメインフォームをインスタンス化し、アクティブにして、スプラッシュフォームを非表示にします。

4

1 に答える 1

1

私が理解している限り、Application.Run()フォームを表示する前に具体的に呼び出す必要があります。これは、ウィンドウメッセージループ/ポンプを起動し、基本的にUI用に別のスレッドを生成するためです。

そうしないと、フォームはメッセージを処理したりペイントしたりできなくなります。

私の提案は、メインフォームをロードし、通常の処理を実行する前にメインフォームにスプラッシュ画面を呼び出させることFormLoadです。ライセンスが失敗した場合は、を呼び出しApplication.Exit()returnからFormLoad外すことができるため、ユーザーが使用する前にアプリをシャットダウンできます。

編集:メインフォームはFormLoad終了するまで表示されないため、スプラッシュ画面が表示されている間はメインフォームが非表示になることを心配する必要はありません。

編集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の記事をご覧ください。私がここでやったことよりもうまくやっています。

于 2010-07-09T21:00:09.380 に答える