ゆうなんとかさんの雑記帳的な。

Twitterで踊ったり音ゲーしたりしてるあの名前がよくわからない人が書いてるらしいよ。

WPFのスプラッシュスクリーンを明示的に制御する方法

WPFのスプラッシュスクリーンは画像のプロパティをちょちょいといじってやれば超簡単に出せるのですが、そのかわりデフォルトでは出現・消滅のタイミングはまったくもって制御できません。今回はこれを何とかしてやろうじゃないかというお話です。

WPFのスプラッシュスクリーンが出てくるタイミング

プロジェクトからは見えない「obj」というフォルダーの下に「App.g.i.cs」というコードが自動生成されているので、それを見てみましょう。そこにMain()というメソッドがあるのですが、それがWPFアプリのエントリーポイントです。だいたいこんな感じ。

/// <summary>
/// Application Entry Point.
/// </summary>
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
public static void Main() {
    Sample.App app = new Sample.App();
    app.InitializeComponent();
    app.Run();
}

これ、スプラッシュスクリーンを表示するように設定してあると、まずやることはスプラッシュスクリーンのインスタンスを作ってShowすることなんです。本当に何よりも先にやります

/// <summary>
/// Application Entry Point.
/// </summary>
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
public static void Main() {
    SplashScreen splashScreen = new SplashScreen("path/to/image.png");
    splashScreen.Show(true);
    Sample.App app = new Sample.App();
    app.InitializeComponent();
    app.Run();
}

そのあと、Appクラスのインスタンスを作ってアプリを起動しています。
そこまではいい。でもなぜスプラッシュスクリーンを制御できないかというと、見ての通りスプラッシュスクリーンのインスタンスローカル変数で作っちゃうからです。隠したいけど触れない。そりゃ無理だ。
というわけで、微妙なタイミングでスプラッシュスクリーンを制御したいなら、どうするかというと、話は簡単でAppクラスのコンストラクターで真っ先にスプラッシュスクリーンを作ってShowしてしまえばいいわけです。

private SplashScreen screen;

public App : base()
{
    screen = new SplashScreen("path/to/image.png");
    screen.Show(trje);
    // なんかする
}

Applicationクラスのデフォルトコンストラクターが何しているかによりますが、標準のスプラッシュスクリーンの出し方とと比べて遜色ない速さで出せます、たぶん。少なくとも私はその差がほとんどわかりませんでした。

なんでこんなことを…

スプラッシュスクリーンの消えるタイミングを制御したいわけがあって対処しないといけなかったんです。具体的には親窓のスプラッシュスクリーンを出す→ちょっと案内をするウィンドウを出すというのをやりたかったのですが、スプラッシュスクリーンをなすがままにしていると案内ウィンドウにスプラッシュスクリーンが覆いかぶさるという残念な事態になってしまいました。AppクラスのコンストラクターでささっとShowさせてしまえば、Applicationクラスのデフォルトコンストラクターの処理が劇重でない限り、本来のスプラッシュスクリーンの出し方に比べても人間にはわからないレベルの遅延しか起きないはずですしね。今回は1msecでも早くスプラッシュスクリーンを出すことのメリットよりもそれよりもスプラッシュスクリーンの閉じるタイミングを明示的に制御できるメリットのほうが大きかったのでこういう選択をしました。