Feed on
Posts
Comments

普通にBackground変更するだけでよくねって思ってたらかなり面倒なテロが混じってました

というわけでWindows StoreのBackgroundを変更したいって要望があるとします、いつものあれです
いや別にほかの色にするとかでもいいんですけども

面倒なので今回はListBoxの背景を青にします

xamlは大体こんな感じで

<ListBox ... Background="#CC00FFE8"/>

…のところは省略しました
カラーコードべた書きとかマジとか言われそうですが今回はそこが問題じゃないのでスルーで

これで実行するとこんな感じになります

fspic140430-2

はい、センスが残念ですがとりあえず色は変わっております

なんだー問題ないじゃんって思ってアイテムを選択するとこのようになります
fspic140430-3
なんとセンスが悪い色が消滅して元の色に変化します!
ちなみにさっきの色は一度でも変更がかかるともう一度プロパティから指定しない限り色はデフォルトにされてしまいます

つまりListBoxの背景色を変更する場合はフォーカス不能にすればいいんですね! ってそんなのわざわざ作る必要がないという

じゃあどうやって直すのか?ってなるとStyleから変更する必要があります

・ListBoxのStyle
既定のStyleはどうなってるの?っていうとMSDN見るとこんな感じ
ListBox styles and templates (Windows)

<!-- Default style for Windows.UI.Xaml.Controls.ListBox -->
<Style TargetType="ListBox">
    <Setter Property="Foreground" Value="{ThemeResource ListBoxForegroundThemeBrush}" />
    <Setter Property="Background" Value="{ThemeResource ListBoxBackgroundThemeBrush}" />
    <Setter Property="BorderBrush" Value="{ThemeResource ListBoxBorderThemeBrush}" />
    <Setter Property="BorderThickness" Value="{ThemeResource ListBoxBorderThemeThickness}" />
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
    <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
    <Setter Property="ScrollViewer.IsHorizontalRailEnabled" Value="True" />
    <Setter Property="ScrollViewer.VerticalScrollMode" Value="Enabled" />
    <Setter Property="ScrollViewer.IsVerticalRailEnabled" Value="True" />
    <Setter Property="ScrollViewer.ZoomMode" Value="Disabled" />
    <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
    <Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True" />
    <Setter Property="IsTabStop" Value="False" />
    <Setter Property="TabNavigation" Value="Once" />
    <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
    <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBox">
                <Border x:Name="LayoutRoot" 
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
                                                                   Storyboard.TargetProperty="Background">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Transparent" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
                                                                   Storyboard.TargetProperty="BorderBrush">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxDisabledForegroundThemeBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="FocusStates">
                            <VisualState x:Name="Focused">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
                                                                   Storyboard.TargetProperty="Background">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListBoxFocusBackgroundThemeBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Unfocused"/>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <ScrollViewer x:Name="ScrollViewer"
                                  Padding="{TemplateBinding Padding}"
                                  TabNavigation="{TemplateBinding TabNavigation}"
                                  HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
                                  HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
                                  VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
                                  VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
                                  IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
                                  IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
                                  ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
                                  IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
                                  BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
                                  AutomationProperties.AccessibilityView="Raw">
                        <ItemsPresenter />
                    </ScrollViewer>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

ここで注目すべきはControlTemplateのVisualStateManagerです

ListBoxはBorder, ScrollViewer, ItemsPresenterという順で重なっていて一番下がBorderです
このBorderのBackgroundがListBoxで指定したBackgroundになるのですが、とても残念なことにVisualStateがFocusedに変わるとBackgroundの値は既定の値に書き換えられています
どういう理由でこうなってるのかはよくわかりませんが、これだとListBoxのプロパティをどんなに頑張ってもフォーカスした時点で変更されます

じゃあどうするの~っていうといくつか手段はあると思いますが、基本的にはStyleのVisualStateの内容を変更するかTemplateBindingの場所を入れ替えるのがよさそうかなと

VisualStateをいじる場合は完全にカスタマイズする必要がありますが一番丁寧な表現ができるかなと思います
フォーカスがない時の状態なども正しく指定できますし

でもそんなの面倒!って場合はTemplateBindingの位置を変更しましょう
今、LayoutRootに{TemplateBinding Background}は指定されています
そもそもここにBackgroundを指定するから背景が上書きされてしまうのでこのTemplateBindingをScrollViewerのBackgroundに動かします
つまり<ScrollViewer Background={TemplateBinding Background}…という感じに追加してBorderのほうからは消せばScrollViewerはBorderより上に存在しているのでBorderの背景が変わろうとさして問題にはなりません

この場合だとListBoxのBackgroundを{x:Null}にするとデフォルトの背景色の設定が使えるのでデフォルトも使うという場合はこういう感じがいいのかなーと


というわけでただのメモ書きな感じです
わざわざStyleを変更しないと設定できないってうーむとも思いつつ

ちなみにさっきの方法はどっちかっていうとImageBrushなどの設定には使いやすいですがSolidColorBrushとかの設定だと裏に色が残るので注意して使わないと変な色になります

あと個人的に背景に画像を出すときは地の背景色が白系ならOpacity 0.2で黒系なら0.4くらいが文字も見やすくていいかなと思います
画像次第ですけど

この辺で

Comments are closed.