プログラムの事とか

お約束ですが「掲載内容は私個人の見解です」

UWPで動的にスタイルを変更する

f:id:puni-o:20160425183123j:plain

UWPのXAMLではDynamicResourceが指定できないので無理ですね。(DynamicResourceないよね・・?) おしまい。

それっぽくがんばる

ということでそれっぽく頑張ります。

まずは準備 f:id:puni-o:20160425183453p:plain

App.xaml

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Styles/StandardStyle.xaml" />
            <ResourceDictionary Source="Styles/BlueTheme.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

BlueTheme.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <SolidColorBrush x:Name="MyBrush" Color="Blue"/>
</ResourceDictionary>

こんな感じ。

StandardStyle.xamlには共通のスタイルが入っているつもりです。(今回は空)

Blue(Green/Red)Theme.xamlにはそれぞれのテーマが定義してあります。(RedとGreenにはそれぞれの色が定義されています)

MainPage.xaml

<Page>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <StackPanel Orientation="Horizontal">
            <Button Content="Blue" Click="Button_Click"/>
            <Button Content="Green" Click="Button_Click"/>
            <Button Content="Red" Click="Button_Click"/>
        </StackPanel>
        <Border Grid.Row="1" Background="{StaticResource MyBrush}"/>
        <ListBox Grid.Row="1" Grid.Column="1">
            <ListBoxItem>1</ListBoxItem>
            <ListBoxItem>2</ListBoxItem>
            <ListBoxItem>3</ListBoxItem>
            <ListBoxItem>4</ListBoxItem>
        </ListBox>
    </Grid>
</Page>

Button_Clickイベントでテーマ(Blue/Green/Red)を切り替えます。リストボックスはなんとなく置いてあります。

切り替える部分はこんな感じ。

private void Button_Click(object sender, RoutedEventArgs e)
{
    var themeUri = new Uri($"ms-appx:/Styles/{(sender as Button).Content}Theme.xaml");
    ChangeTheme(themeUri);
}

private void ChangeTheme(Uri theme)
{
    var starndard = new ResourceDictionary { Source = new Uri("ms-appx:/Styles/StandardStyle.xaml") };
    var custom = new ResourceDictionary { Source = theme };
    var main = new ResourceDictionary();
    main.MergedDictionaries.Add(starndard);
    main.MergedDictionaries.Add(custom);
    App.Current.Resources = main;

    var frame = Window.Current.Content as Frame;
    frame.Navigate(frame.Content.GetType());
    frame.GoBack();
}

Button_ClickイベントでリソースへのUriを作ってChangeThemeを呼びます。

ChangeThemeで新しいリソースディクショナリ作って画面遷移(して戻ってきている)で終了。

リソースディクショナリを変更してコントロールを作り直しているってことですね。 実行イメージはこんな感じ

f:id:puni-o:20160425184603g:plain

Borderの背景色が変わっていることとListBoxの選択状態が解除されている(初期状態に戻っている)事がわかりますね。

という方法を

Jerry Nixon on Windows: Walkthrough: Dynamically Skinning your Windows 8 App

ここで見つけたんですがこれでいいんですかね~~~、よくわかりません。 おしまい