HIDARI日記(右)

そのときどき興味ある技術を中心にだらだら書いてます。内容は個人の見解であり、所属する企業を代表するものではありません。

OnStartupをオーバーライドしたらApplication.Resourcesに設定したStyleやらDataTemplateが適用されなかった話

きっかけ

MVVM入門 その1「シンプル四則演算アプリケーションの作成」 in C#, XAML for Visual Studio 2010

のサンプルで,Startupイベントのイベントハンドラ(Application_Startup)でやろうとしてる処理を,overrideしたOnStartイベントハンドラだけで行おうとしたけど,なぜかApp.xaml内のDataTemplateがうまく適用されなかったので,回避方法を模索してみました.

シンプルに再現してみる

まずはVisual Studioで適当にWPFアプリケーションを作成して,MainWindow.xamlにTextBlockのみを置いて実行してみます.

<Grid>
    <TextBlock Text="HogeHoge"/>
</Grid>

こんな感じですね.

f:id:hidari-yori:20140129150950j:plain

このように表示されます.

では次にこれに適当なStyleを定義しましょう.App.xamlのApplication.Resourcesに追加しましょう.

<Application.Resources>
    <Style TargetType="TextBlock">
        <Setter Property="Background" Value="PaleVioletRed"/>
    </Style>
</Application.Resources>

実行するとげろげろな色になるのが確認できます.

f:id:hidari-yori:20140129151023j:plain

ここから,StartupUriを使わず自前でMainWindowを表示するように変更します.

App.xamlのApplication要素からStartupUri属性を削除.

<Application x:Class="WpfApplication2.Views.App"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" /> <Application.Resources>

AppクラスでOnStartupイベントハンドラをオーバーライドして,MainWindowをShowします.

/// <summary>
/// App.xaml の相互作用ロジック
/// </summary>
public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        var window = new MainWindow();
        window.Show();
    }
}

本来ならこれは先ほどと同じげろげろな色で表示されるはずですが

f:id:hidari-yori:20140129151120j:plain

Styleさん,息してません.

適用させるには

手っ取り早くStyleを適用させるにはStartupイベントにイベントハンドラを設定します.Visual Studioイベントハンドラを生成してくれて楽ですし.

<Application x:Class="WpfApplication2.Views.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Startup="Application_Startup">

コードビハインド(App.xaml.cs)にこんなのが追加されています.

private void Application_Startup(object sender, StartupEventArgs e)
{

}

中身の無いApplication_Startupメソッドですね.これで実行すると

f:id:hidari-yori:20140129151317j:plain

適用されていますね.

もう一つの方法としては,外部のResourceDictionaryに移してしまい,それをSource属性を使って読み込む方法です.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style TargetType="TextBlock">
        <Setter Property="Background" Value="PaleVioletRed"/>
    </Style>
</ResourceDictionary>

という内容のDictionary1.xaml

<Application.Resources>
    <ResourceDictionary Source="Views/Dictionary1.xaml"/>
</Application.Resources>

とすることでもうまく適用されます.

結局

回避する方法としては,

  • 大人しくStartupUriのお世話になる
  • 何も考えずStartupイベントのイベントハンドラを設定する
  • ResouceDictionaryを外部ファイルに追い出す

とかでしょうか.ちなみに3番目が好み.

とりあえず僕にわかったのはここまでです.結局原因はわからなかったので誰か教えてください.私,気になります!

おまけ

先日の Room metro #22@yone64 さんに教えて貰ったのですが,App.xamlにStartupを書かず,コードビハインドにApplication_Startupメソッドだけが定義されてる状態でもStyleが適用されるという謎の挙動をします.

なにか闇を見た気がします.