Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify WPF Toolkit DropDownButton style

Tags:

c#

wpf

wpftoolkit

I am trying to modify WpfToolkit's DropDownButton style in order to allow me to set the Background color.

Here is the default style of the DropDownButton:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:chrome="clr-namespace:Xceed.Wpf.Toolkit.Chromes"
                    xmlns:conv="clr-namespace:Xceed.Wpf.Toolkit.Core.Converters"
                    xmlns:local="clr-namespace:Xceed.Wpf.Toolkit">

   <conv:InverseBoolConverter x:Key="InverseBoolConverter" />

   <LinearGradientBrush x:Key="PopupDarkBorderBrush" EndPoint="0.5,1" StartPoint="0.5,0">
      <GradientStop Color="#FFA3AEB9" Offset="0" />
      <GradientStop Color="#FF8399A9" Offset="0.375" />
      <GradientStop Color="#FF718597" Offset="0.375" />
      <GradientStop Color="#FF617584" Offset="1" />
   </LinearGradientBrush>

   <LinearGradientBrush x:Key="PopupBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
      <LinearGradientBrush.GradientStops>
         <GradientStopCollection>
            <GradientStop Offset="0" Color="#FFffffff" />
            <GradientStop Offset="1" Color="#FFE8EBED" />
         </GradientStopCollection>
      </LinearGradientBrush.GradientStops>
   </LinearGradientBrush>

   <Style TargetType="{x:Type local:DropDownButton}">
      <Setter Property="BorderThickness" Value="1" />
      <Setter Property="IsTabStop" Value="False" />
      <Setter Property="HorizontalContentAlignment" Value="Center" />
      <Setter Property="VerticalContentAlignment" Value="Center" />
      <Setter Property="Padding" Value="3" />
      <Setter Property="Template">
         <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:DropDownButton}">
               <Grid x:Name="MainGrid" SnapsToDevicePixels="True">
                  <ToggleButton x:Name="PART_DropDownButton"
                                Grid.Column="1"
                                IsChecked="{Binding IsOpen, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
                                IsHitTestVisible="{Binding IsOpen, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource InverseBoolConverter}}">
                     <ToggleButton.Template>
                        <ControlTemplate TargetType="ToggleButton">
                           <ContentPresenter />
                        </ControlTemplate>
                     </ToggleButton.Template>
                     <Grid>
                        <chrome:ButtonChrome x:Name="ToggleButtonChrome"
                                             CornerRadius="2.75"
                                             RenderChecked="{TemplateBinding IsOpen}"
                                             RenderEnabled="{TemplateBinding IsEnabled}"
                                                        RenderMouseOver="{Binding IsMouseOver, ElementName=PART_DropDownButton}"
                                                        RenderPressed="{Binding IsPressed, ElementName=PART_DropDownButton}">
                           <Grid>
                              <Grid.ColumnDefinitions>
                                 <ColumnDefinition Width="*" />
                                 <ColumnDefinition Width="Auto" />
                              </Grid.ColumnDefinitions>
                              <ContentPresenter Margin="{TemplateBinding Padding}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="true" />
                              <Grid x:Name="arrowGlyph" IsHitTestVisible="False" Margin="4,3,4,3" Grid.Column="1">
                                 <Path x:Name="Arrow"  Width="7" Height="4" Data="M 0,1 C0,1 0,0 0,0 0,0 3,0 3,0 3,0 3,1 3,1 3,1 4,1 4,1 4,1 4,0 4,0 4,0 7,0 7,0 7,0 7,1 7,1 7,1 6,1 6,1 6,1 6,2 6,2 6,2 5,2 5,2 5,2 5,3 5,3 5,3 4,3 4,3 4,3 4,4 4,4 4,4 3,4 3,4 3,4 3,3 3,3 3,3 2,3 2,3 2,3 2,2 2,2 2,2 1,2 1,2 1,2 1,1 1,1 1,1 0,1 0,1 z" Fill="#FF000000" />
                              </Grid>
                           </Grid>
                        </chrome:ButtonChrome>
                     </Grid>
                  </ToggleButton>

                  <Popup x:Name="PART_Popup" 
                         HorizontalOffset="1"
                         VerticalOffset="1"
                         AllowsTransparency="True"
                         StaysOpen="False"
                         Placement="Bottom"
                         Focusable="False"
                         IsOpen="{Binding IsChecked, ElementName=PART_DropDownButton}">
                     <Border BorderThickness="1" Background="{StaticResource PopupBackgroundBrush}" BorderBrush="{StaticResource PopupDarkBorderBrush}">
                        <ContentPresenter x:Name="PART_ContentPresenter" Content="{TemplateBinding DropDownContent}" />
                     </Border>
                  </Popup>

               </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Fill" TargetName="Arrow" Value="#AFAFAF" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
         </Setter.Value>
      </Setter>
   </Style>
</ResourceDictionary>

I am creating the DropDownButton like so:

<extToolkit:DropDownButton VerticalAlignment="Center" Background="Red">
            <extToolkit:DropDownButton.Content>
                <TextBlock>Click me</TextBlock>
            </extToolkit:DropDownButton.Content>
            <extToolkit:DropDownButton.DropDownContent>
                <TextBlock>Popup</TextBlock>
            </extToolkit:DropDownButton.DropDownContent>
        </extToolkit:DropDownButton>

I set the Background to Red but that doesn't have any impact. So I tried to set the Background of the DropDownButton's style to bind to the Background I set:

<Grid Background="{TemplateBinding Background}">
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="*" />
                                                <ColumnDefinition Width="Auto" />
                                            </Grid.ColumnDefinitions>
                                            <ContentPresenter Margin="{TemplateBinding Padding}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="true" />
                                            <Grid x:Name="arrowGlyph" IsHitTestVisible="False" Margin="4,3,4,3" Grid.Column="1">
                                                <Path x:Name="Arrow"  Width="7" Height="4" Data="M 0,1 C0,1 0,0 0,0 0,0 3,0 3,0 3,0 3,1 3,1 3,1 4,1 4,1 4,1 4,0 4,0 4,0 7,0 7,0 7,0 7,1 7,1 7,1 6,1 6,1 6,1 6,2 6,2 6,2 5,2 5,2 5,2 5,3 5,3 5,3 4,3 4,3 4,3 4,4 4,4 4,4 3,4 3,4 3,4 3,3 3,3 3,3 2,3 2,3 2,3 2,2 2,2 2,2 1,2 1,2 1,2 1,1 1,1 1,1 0,1 0,1 z" Fill="#FF000000" />
                                            </Grid>
                                        </Grid>

But that didn't change the background color, no matter what I set in my control. If I set the Background color directly in the style (no binding), then the color takes affect but for some reason the CornerRadius defined on ButtonChrome disappears and the button reverts to a rectangle.

Any suggestions? I just want to be able to set the background of the drop down button and the PART_Popup when defining the control.

like image 555
Flack Avatar asked Feb 11 '14 21:02

Flack


1 Answers

It seems that ButtonChrome can not set an arbitrary Background color without losing the CornerRadius property. If you do not like it, then you need to look for an alternative, as an alternative, I have used ToggleButton for this:

<ToggleButton x:Name="ToggleButtonChrome"
              Background="{TemplateBinding Background}"
              IsEnabled="{TemplateBinding IsEnabled}"
              IsChecked="{Binding IsOpen, ElementName=PART_Popup}">

but I have a icon Button stands in the middle, for me no methods do not get rid of it, so I'm in Content property compensated by its spaces:

Content=" Click me         " 

To set the Background for Popup, I created an attached dependency property Background, which is in PropertyExtension namespace:

public static class Popup
{
    #region Popup Background Property

    public static readonly DependencyProperty BackgroundProperty;

    public static void SetBackground(DependencyObject DepObject, Brush value)
    {
        DepObject.SetValue(BackgroundProperty, value);
    }

    public static Brush GetBackground(DependencyObject DepObject)
    {
        return (Brush)DepObject.GetValue(BackgroundProperty);
    }

    #endregion

    static Popup()
    {
        #region Popup Background Registration

        PropertyMetadata BrushPropertyMetadata = new PropertyMetadata(Brushes.Transparent);

        BackgroundProperty = DependencyProperty.RegisterAttached("Background",
                                                         typeof(Brush),
                                                         typeof(Popup),
                                                         BrushPropertyMetadata);

        #endregion
    }
}

And set in the ControlTemplate as follows:

<Popup x:Name="PART_Popup"
       IsOpen="{Binding IsChecked, ElementName=PART_DropDownButton}"
       ...>                                
    <Border BorderThickness="1"
            Background="{TemplateBinding PropertyExtension:Popup.Background}"> <!-- Here -->

        <ContentPresenter x:Name="PART_ContentPresenter" 
                          Content="{TemplateBinding DropDownContent}" />
    </Border>
</Popup>

Example of using:

<Grid>
    <wpfx:DropDownButton PropertyExtension:Popup.Background="{StaticResource PopupBackground}"
                         Content=" Click me         " 
                         HorizontalContentAlignment="Left"
                         Background="CadetBlue"
                         Width="80" 
                         Height="30" >

        <wpfx:DropDownButton.DropDownContent>
            <TextBlock Width="100" 
                       Height="100"
                       Text="Popup" />
        </wpfx:DropDownButton.DropDownContent>
    </wpfx:DropDownButton>
</Grid>

The initial state:

enter image description here

The final state:

enter image description here

The whole project is available on this link.

Below a full example:

<Window.Resources>
    <wpfx:InverseBoolConverter x:Key="InverseBoolConverter" />
    <SolidColorBrush x:Key="PopupBackground" Color="Beige" />

    <Style TargetType="{x:Type wpfx:DropDownButton}">
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="IsTabStop" Value="False" />

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type wpfx:DropDownButton}">
                    <Grid x:Name="MainGrid"                                              
                          SnapsToDevicePixels="True">

                        <ToggleButton x:Name="PART_DropDownButton"
                                      Grid.Column="1"
                                      IsChecked="{Binding IsOpen, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
                                      IsHitTestVisible="{Binding IsOpen, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource InverseBoolConverter}}">

                            <ToggleButton.Template>
                                <ControlTemplate TargetType="ToggleButton">
                                    <ContentPresenter />
                                </ControlTemplate>
                            </ToggleButton.Template>

                            <Grid>
                                <ToggleButton x:Name="ToggleButtonChrome"
                                              Background="{TemplateBinding Background}"
                                              IsEnabled="{TemplateBinding IsEnabled}"
                                              IsChecked="{Binding IsOpen, ElementName=PART_Popup}">

                                    <Grid>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="*" />
                                            <ColumnDefinition Width="Auto" />
                                        </Grid.ColumnDefinitions>

                                        <ContentPresenter Content="{TemplateBinding Content}" 
                                                          ContentTemplate="{TemplateBinding ContentTemplate}"  
                                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                                          RecognizesAccessKey="True" />

                                        <Grid x:Name="arrowGlyph" 
                                              IsHitTestVisible="False" 
                                              Margin="4,3,4,3"                                                  
                                              Grid.Column="1">

                                            <Path x:Name="Arrow"
                                                  Width="7" 
                                                  Height="4"
                                                  Data="M 0,1 C0,1 0,0 0,0 0,0 3,0 3,0 3,0 3,1 3,1 3,1 4,1 4,1 4,1 4,0 4,0 4,0 7,0 7,0 7,0 7,1 7,1 7,1 6,1 6,1 6,1 6,2 6,2 6,2 5,2 5,2 5,2 5,3 5,3 5,3 4,3 4,3 4,3 4,4 4,4 4,4 3,4 3,4 3,4 3,3 3,3 3,3 2,3 2,3 2,3 2,2 2,2 2,2 1,2 1,2 1,2 1,1 1,1 1,1 0,1 0,1 z" 
                                                  Fill="#FF000000" />
                                        </Grid>
                                    </Grid>
                                </ToggleButton>
                            </Grid>
                        </ToggleButton>

                        <Popup x:Name="PART_Popup"
                               IsOpen="{Binding IsChecked, ElementName=PART_DropDownButton}"
                               HorizontalOffset="1"
                               VerticalOffset="1"
                               AllowsTransparency="True"
                               StaysOpen="False"
                               Placement="Bottom"
                               Focusable="False">

                            <Border BorderThickness="1"
                                    Background="{TemplateBinding PropertyExtension:Popup.Background}">

                                <ContentPresenter x:Name="PART_ContentPresenter" 
                                                  Content="{TemplateBinding DropDownContent}" />
                            </Border>
                        </Popup>
                    </Grid>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="Fill" TargetName="Arrow" Value="#AFAFAF" />
                        </Trigger>                            
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<Grid>
    <wpfx:DropDownButton PropertyExtension:Popup.Background="{StaticResource PopupBackground}"
                         Content=" Click me         " 
                         HorizontalContentAlignment="Left"
                         Background="CadetBlue"
                         Width="80" 
                         Height="30" >

        <wpfx:DropDownButton.DropDownContent>
            <TextBlock Width="100" 
                       Height="100"
                       Text="Popup" />
        </wpfx:DropDownButton.DropDownContent>
    </wpfx:DropDownButton>
</Grid>
like image 84
Anatoliy Nikolaev Avatar answered Nov 01 '22 23:11

Anatoliy Nikolaev