ComboBox の編集時のみ背景色を変更する



WindowsForms のアプリを WPF に移植しようとして、またまた引っかかったが、ComboBox 編集時の背景色変更。
TextBox なら 以下のようにトリガーで簡単に設定できるのですが、ComboBox の場合はそうもいきません。

<Style TargetType="{x:Type TextBox}">
	<Style.Triggers>
		<Trigger Property="IsFocused" Value="true">
			<Setter Property="Background" Value="LemonChiffon"/>
		</Trigger>
	</Style.Triggers>
</Style>


ComboBox の場合、以下のようにトリガーを設定しても、IsEdiable=false (WinForm なら DropDownList) なら問題ないですが、IsEdiable=true (WinForm の DropDown) にした ComboBox では Background に設定したブラシは反映されません。

<Style TargetType="{x:Type ComboBox}">
	<Style.Triggers>
		<Trigger Property="IsFocused" Value="true">
			<Setter Property="Background" Value="LemonChiffon"/>
		</Trigger>
	</Style.Triggers>
</Style>


(2011/04/23 修正)
これは ComboBox の構造的問題によるもので、IsEdiable な ComboBox でフォーカス時にのみ Background を設定したいなら ControlTemplate を編集する以外ありませんか、もしくは IsKeyboardFocusWithin プロパティを使います。

<Style TargetType="{x:Type ComboBox}">
	<Style.Triggers>
		<Trigger Property="IsKeyboardFocusWithin" Value="true">
			<Setter Property="Background" Value="LemonChiffon"/>
		</Trigger>
	</Style.Triggers>
</Style>

上記のように、IsFocused の代わりに IsKeyboardFocusWithin プロパティを使うと Background の設定がビューに反映されます。これだとテンプレートを編集する必要がないので手っ取り早いです。



もしくは ControlTemplate を編集する方法もあります。 2011/04/23 修正 時点ではもはや古い解決方法になるのですが、なにかの参考までに一応残しておきます。
ComboBox の Template 内の ComboBoxEditableTextBox というリソースを探し、Template の設定に以下のトリガを加えます。この例では Yellow を設定しました。

<ControlTemplate.Triggers>
	<Trigger Property="IsFocused" Value="True">
		<Setter Property="Background" TargetName="PART_ContentHost" Value="Yellow" />
	</Trigger>
</ControlTemplate.Triggers>


するとこうなります。


以下 スタイルの全文です。

<Style x:Key="ComboBoxFocusVisual">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>
                <Rectangle Margin="4,4,21,4" SnapsToDevicePixels="true" 
                            Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" 
                            StrokeThickness="1" StrokeDashArray="1 2"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<SolidColorBrush x:Key="ListBorder" Color="#FF7F9DB9"/>
<Style x:Key="ComboBoxTransparentButtonStyle" TargetType="{x:Type ToggleButton}">
    <Setter Property="MinWidth" Value="0"/>
    <Setter Property="MinHeight" Value="0"/>
    <Setter Property="Width" Value="Auto"/>
    <Setter Property="Height" Value="Auto"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Focusable" Value="false"/>
    <Setter Property="ClickMode" Value="Press"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <Grid Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition SharedSizeGroup="ComboBoxButton" Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Microsoft_Windows_Themes:ScrollChrome x:Name="Chrome" 
                            Grid.Column="1" HasOuterBorder="false" Padding="1,0,0,0" 
                            RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsChecked}" 
                            Microsoft_Windows_Themes:ScrollChrome.ScrollGlyph="DownArrow" ThemeColor="NormalColor"
                            Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="ComboBoxEditableTextBox" TargetType="{x:Type TextBox}">
    <Setter Property="OverridesDefaultStyle" Value="true"/>
    <Setter Property="AllowDrop" Value="true"/>
    <Setter Property="MinWidth" Value="0"/>
    <Setter Property="MinHeight" Value="0"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
    <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <ScrollViewer x:Name="PART_ContentHost" Background="Transparent" 
                        Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsFocused" Value="True">
                        <Setter Property="Background" TargetName="PART_ContentHost" Value="Yellow" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<ControlTemplate x:Key="ComboBoxEditableTemplate" TargetType="{x:Type ComboBox}">
    <Grid SnapsToDevicePixels="true">
        <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" 
                        BorderThickness="{TemplateBinding BorderThickness}" 
                        Background="{TemplateBinding Background}" Padding="1">
            <Grid Grid.IsSharedSizeScope="true">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition SharedSizeGroup="ComboBoxButton" Width="Auto"/>
                </Grid.ColumnDefinitions>
                <TextBox x:Name="PART_EditableTextBox" Grid.Column="1" 
                            HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" 
                            IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource TemplatedParent}}" 
                            Margin="{TemplateBinding Padding}" Style="{StaticResource ComboBoxEditableTextBox}" 
                            VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                <ToggleButton Background="{x:Null}" Grid.ColumnSpan="3" 
                            IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, 
                            RelativeSource={RelativeSource TemplatedParent}}" 
                            Style="{StaticResource ComboBoxTransparentButtonStyle}"/>
            </Grid>
        </Border>
        <Popup x:Name="PART_Popup" AllowsTransparency="true" Focusable="false" 
                            IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" 
                            PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" 
                            Placement="Bottom">
            <Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" 
                            MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{TemplateBinding ActualWidth}">
                <Border x:Name="DropDownBorder" 
                            BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" 
                            BorderThickness="1" 
                            Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
                    <ScrollViewer x:Name="DropDownScrollViewer">
                        <Grid RenderOptions.ClearTypeHint="Enabled">
                            <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
                                <Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=DropDownBorder}" 
                                    Height="{Binding ActualHeight, ElementName=DropDownBorder}" 
                                    Width="{Binding ActualWidth, ElementName=DropDownBorder}"/>
                            </Canvas>
                            <ItemsPresenter x:Name="ItemsPresenter" 
                                    KeyboardNavigation.DirectionalNavigation="Contained" 
                                    SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </Grid>
                    </ScrollViewer>
                </Border>
            </Microsoft_Windows_Themes:SystemDropShadowChrome>
        </Popup>
    </Grid>
    <ControlTemplate.Triggers>
        <Trigger Property="HasItems" Value="false">
            <Setter Property="MinHeight" TargetName="DropDownBorder" Value="95"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
            <Setter Property="Background" TargetName="Bd" 
                    Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
        </Trigger>
        <Trigger Property="IsGrouping" Value="true">
            <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
        </Trigger>
        <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
            <Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
            <Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
        </Trigger>
        <Trigger Property="ScrollViewer.CanContentScroll" SourceName="DropDownScrollViewer" Value="false">
            <Setter Property="Canvas.Top" TargetName="OpaqueRect" 
                    Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}"/>
            <Setter Property="Canvas.Left" TargetName="OpaqueRect" 
                    Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>
<Style TargetType="{x:Type ComboBox}">
    <Setter Property="FocusVisualStyle" Value="{StaticResource ComboBoxFocusVisual}"/>
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
    <Setter Property="BorderBrush" Value="{StaticResource ListBorder}"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Padding" Value="1"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
    <Setter Property="ScrollViewer.PanningMode" Value="Both"/>
    <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ComboBox}">
                <Grid SnapsToDevicePixels="true">
                    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" 
                        BorderThickness="{TemplateBinding BorderThickness}" 
                        Background="{TemplateBinding Background}" Padding="1">
                        <Grid Grid.IsSharedSizeScope="true">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="1"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition SharedSizeGroup="ComboBoxButton" Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <Border x:Name="SelectedItemBorder" Grid.ColumnSpan="2" Margin="{TemplateBinding Padding}"/>
                            <ContentPresenter ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" 
                                ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" 
                                Content="{TemplateBinding SelectionBoxItem}" Grid.Column="1" 
                                ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" 
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                Margin="{TemplateBinding Padding}" 
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            <ToggleButton Grid.ColumnSpan="3" IsChecked="{Binding IsDropDownOpen, 
                                Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" 
                                Style="{StaticResource ComboBoxTransparentButtonStyle}"/>
                        </Grid>
                    </Border>
                    <Popup x:Name="PART_Popup" AllowsTransparency="true" 
                                Focusable="false" IsOpen="{Binding IsDropDownOpen, 
                                RelativeSource={RelativeSource TemplatedParent}}" 
                                PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" 
                                Placement="Bottom">
                        <Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" 
                                Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" 
                                MinWidth="{TemplateBinding ActualWidth}">
                            <Border x:Name="DropDownBorder" 
                                BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" 
                                BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
                                <ScrollViewer x:Name="DropDownScrollViewer">
                                    <Grid RenderOptions.ClearTypeHint="Enabled">
                                        <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
                                            <Rectangle x:Name="OpaqueRect" 
                                                Fill="{Binding Background, ElementName=DropDownBorder}" 
                                                Height="{Binding ActualHeight, ElementName=DropDownBorder}" 
                                                Width="{Binding ActualWidth, ElementName=DropDownBorder}"/>
                                        </Canvas>
                                        <ItemsPresenter x:Name="ItemsPresenter" 
                                            KeyboardNavigation.DirectionalNavigation="Contained" 
                                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                    </Grid>
                                </ScrollViewer>
                            </Border>
                        </Microsoft_Windows_Themes:SystemDropShadowChrome>
                    </Popup>
                </Grid>
                <ControlTemplate.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsSelectionBoxHighlighted" Value="true"/>
                            <Condition Property="IsDropDownOpen" Value="false"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="Foreground" 
                            Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                    </MultiTrigger>
                    <Trigger Property="IsSelectionBoxHighlighted" Value="true">
                        <Setter Property="Background" TargetName="SelectedItemBorder" 
                            Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                    </Trigger>
                    <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
                        <Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
                        <Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
                    </Trigger>
                    <Trigger Property="HasItems" Value="false">
                        <Setter Property="MinHeight" TargetName="DropDownBorder" Value="95"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" 
                            Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        <Setter Property="Background" TargetName="Bd" 
                            Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                    </Trigger>
                    <Trigger Property="IsGrouping" Value="true">
                        <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                    </Trigger>
                    <Trigger Property="ScrollViewer.CanContentScroll" 
                            SourceName="DropDownScrollViewer" Value="false">
                        <Setter Property="Canvas.Top" TargetName="OpaqueRect" 
                            Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}"/>
                        <Setter Property="Canvas.Left" TargetName="OpaqueRect" 
                            Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="IsEditable" Value="true">
            <Setter Property="IsTabStop" Value="false"/>
            <Setter Property="Padding" Value="0,1"/>
            <Setter Property="Template" Value="{StaticResource ComboBoxEditableTemplate}"/>
        </Trigger>
    </Style.Triggers>
</Style>


ちなみにテンプレートの編集ですが、Expression Blend があれば、ComboBox を選択して、メニューの「オブジェクト」→「テンプレートの編集」→「コピーして編集」で 「Style リソースの作成」ウィンドウが表示されますので、名前は「すべて適用」、定義先は「このドキュメント」にチェックし、「OK」ボタンをクリックすると Window のリソースにスタイルの定義が展開されますので、これを編集します。