views:

1045

answers:

1

I have a question regarding how to elegantly override an arbitrary element deep inside a control's visual tree. I also have attempted to resolve it in a few different ways, but I've run into several problems with each. Usually when I try three different paths and fail at each one I go downstairs, have a coffee, and ask someone smarter than myself. So here I am.

Specifics:

I want to flatten the style of a combo box so that it will not draw attention to itself. I want it to be similar to Windows.Forms.ComboBox's FlatStyle I want it to look the same on Windows 7 and XP.

Mainly, I want to change the look of a ComboBox's ToggleButton.

I could just use Blend and rip the control template's guts out and manually change them. That doesn't sound very appetizing to me.

I tried using a style to override the ToggleButton's background, but it turns out that the whole ComboBox control is actually a front for a ToggleButton.

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ComboBoxExpiriment2.MainWindow"
x:Name="Window"
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="204" Height="103">
<Grid x:Name="LayoutRoot">
 <ComboBox HorizontalAlignment="Left" Margin="32,26.723,0,0" Width="120" VerticalAlignment="Top" Height="21.277">
 <ComboBox.Style>
   <Style>
    <Setter Property="ToggleButton.Background" Value="Green" />
   </Style>
 </ComboBox.Style>
 </ComboBox>
</Grid>

So I gave up and ripped it using Blend. I found that it's actually a Style called ComboBoxTransparentButtonStyle with a target type of ToggleButton. The style sets a ControlTemplate that uses a DockPanel that has a "Microsoft_Windows_Themes:ClassicBorderDecorator" type set to the right, and that's what we're actually trying to control. (Are you with me so far?)
Here's the pic:

http://img256.imageshack.us/img256/2077/comboboxbackground2.png

<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="BorderBrush" Value="{x:Static Microsoft_Windows_Themes:ClassicBorderDecorator.ClassicBorderBrush}"/>
    <Setter Property="BorderThickness" Value="2"/>
    <Setter Property="Template">
     <Setter.Value>
      <ControlTemplate TargetType="{x:Type ToggleButton}">
       <DockPanel SnapsToDevicePixels="true" Background="{TemplateBinding Background}" LastChildFill="false">
        <Microsoft_Windows_Themes:ClassicBorderDecorator x:Name="Border" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" DockPanel.Dock="Right" Background="Green" BorderBrush="{TemplateBinding BorderBrush}" BorderStyle="None" BorderThickness="{TemplateBinding BorderThickness}">
         <Path Fill="{TemplateBinding Foreground}" HorizontalAlignment="Center" VerticalAlignment="Center" Data="{StaticResource DownArrowGeometry}"/>
        </Microsoft_Windows_Themes:ClassicBorderDecorator>
       </DockPanel>
       <ControlTemplate.Triggers>
        <Trigger Property="IsChecked" Value="true">
         <Setter Property="BorderStyle" TargetName="Border" Value="AltPressed"/>
        </Trigger>
       </ControlTemplate.Triggers>
      </ControlTemplate>
     </Setter.Value>
    </Setter>
    <Style.Triggers>
     <Trigger Property="IsEnabled" Value="false">
      <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
     </Trigger>
    </Style.Triggers>
   </Style>

Arg. Isn't WPF a blast?

So I extracted the style ComboBoxTransparentButtonStyle and dropped it into another project's application.resources. Problem is I can't apply that style to a ComboBox because the style I extracted has a targetType of ToggleButton, so the TargeTypes don't match.

tl;dr how would you guys do it?

+1  A: 

There isn't an elegant solution for this. The best you can do is override the style for the entire ComboBox so that you can change the style it sets for the ToggleButton.

You can use Blend to get the styles, however that probabliy isn't the easiest way. If you have Blend installed, go to "[Program files or where Blend is installed]\SystemThemes\WPF\areo.normalcolor.xaml".

Steven