Search code examples
c#wpfcomboboxtextboxwpf-style

Round combobox style wpf


I wish to construct a custom round ComboBox:

enter image description here

This is the style I'm using:

<Style x:Key="ComboBoxButtonStyle" TargetType="{x:Type ToggleButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <Border Background="White" x:Name="border" CornerRadius="0,5,5,0" BorderThickness="0,2,2,2" BorderBrush="Black">
                    <ContentPresenter />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="ComboBoxTextBoxStyle" TargetType="{x:Type TextBox}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Grid>
                    <Border CornerRadius="5,0,0,5" BorderThickness="2,2,0,2" Background="{TemplateBinding Background}"                                  BorderBrush="Black">
                        <ScrollViewer x:Name="PART_ContentHost"/>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="RoundComboBoxStyle" TargetType="{x:Type ComboBox}">
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ComboBox}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition MaxWidth="18"/>
                    </Grid.ColumnDefinitions>
                    <TextBox Name="PART_EditableTextBox" IsEnabled="False" Style="{StaticResource ComboBoxTextBoxStyle}" Padding="5,0,0,0" Height="{TemplateBinding Height}"/>
                    <ToggleButton Grid.Column="1" Margin="0" Height="{TemplateBinding Height}" Style="{StaticResource ComboBoxButtonStyle}" Focusable="False"  
                                    IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press">
                        <Path Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M 0 0 L 4 4 L 8 0 Z" Fill="DodgerBlue" />
                    </ToggleButton>
                    <ContentPresenter Grid.Column="0" Name="ContentSite" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"  
                                        ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5,0,0,0"/>
                    <Popup Grid.Column="0" Name="Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="False" Focusable="False" PopupAnimation="Slide">
                        <Grid Name="DropDown" SnapsToDevicePixels="True" MinWidth="{TemplateBinding ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}" >
                            <Border x:Name="DropDownBorder" BorderThickness="1" CornerRadius="5" Background="White" BorderBrush="Black"/>
                            <ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
                                <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
                            </ScrollViewer>
                        </Grid>
                    </Popup>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

The thing is that when I use this style, in order to open the ComboBox and see all the items, I have to click the arrow ToggleButton. I can't click the text, or the TexBox.

So, in order to change that, I edited the 'RoundComboboxStyle' that way:

<Style x:Key="RoundComboBoxStyle" TargetType="{x:Type ComboBox}">
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ComboBox}">
                    <Grid Grid.IsSharedSizeScope="true">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="1"/>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto" SharedSizeGroup="ComboBoxButton"/>
                        </Grid.ColumnDefinitions>
                        <TextBox Name="PART_EditableTextBox" Grid.Column="1" IsReadOnly="{Binding Path=IsReadOnly,RelativeSource={RelativeSource TemplatedParent}}"
                                 Style="{StaticResource ComboBoxTextBoxStyle}" Margin="{TemplateBinding Padding}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                 VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        <ToggleButton Background="{x:Null}" Grid.ColumnSpan="3" Style="{StaticResource ComboBoxButtonStyle}" Opacity="0" Focusable="False" 
                                      IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"/>
                        <ContentPresenter Grid.Column="1" Name="ContentSite" Content="{TemplateBinding SelectionBoxItem}" VerticalAlignment="Center"
                                          ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"  HorizontalAlignment="Center"  
                                          ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Margin="5,0,0,0"/>
                        <Popup Grid.Column="1" Name="Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="False" Focusable="False" PopupAnimation="Slide">
                            <Grid Name="DropDown" SnapsToDevicePixels="True" MinWidth="{TemplateBinding ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}">
                                <Border x:Name="DropDownBorder" BorderThickness="1" CornerRadius="5" Background="White" BorderBrush="Black"/>
                                <ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
                                    <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
                                </ScrollViewer>
                            </Grid>
                        </Popup>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Now, I can click the TextBox to open the ComboBox items list, but I cannot click on the text itself (that does not open the items list).

Also, the ComboBox now looks like this:

enter image description here

Is there a way to combine the two looks and also make the ComboBox behave like a style-less one, in which I can click anywhere on the ComboBox in order to open the list of items?


Solution

  • Well, searched and investigated, and finally found the correct configuration for the style to work. Posting the code:

    <ControlTemplate x:Key="ComboBoxTextBox" TargetType="TextBox">
        <Border x:Name="PART_ContentHost" BorderThickness="1" Focusable="False" Background="{TemplateBinding Background}" />
    </ControlTemplate>
    <ControlTemplate x:Key="ComboBoxToggleButton" TargetType="ToggleButton">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="20" />
            </Grid.ColumnDefinitions>
            <Border x:Name="Border" Grid.ColumnSpan="2" CornerRadius="10,10,10,10" Background="White" BorderBrush="Black" BorderThickness="2" />
            <Path x:Name="Arrow" Grid.Column="1" Fill="DodgerBlue" HorizontalAlignment="Center" VerticalAlignment="Center"
                Data="M 0 0 L 4 4 L 8 0 Z"/>
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="ToggleButton.IsMouseOver" Value="true">
                <Setter TargetName="Border" Property="Background" Value="LightSteelBlue" />
            </Trigger>
            <Trigger Property="ToggleButton.IsChecked" Value="true">
                <Setter TargetName="Border" Property="Background" Value="LightSteelBlue" />
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
    <ControlTemplate x:Key="RoundComboBoxTemplate" TargetType="{x:Type ComboBox}">
        <Grid>
            <Rectangle Stroke="White" RadiusX="10" RadiusY="10" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" 
                        x:Name="Rectangle" Fill="White" />
            <ToggleButton Name="ToggleButton" Template="{StaticResource ComboBoxToggleButton}" Height="{TemplateBinding Height}" Focusable="False"
                            ClickMode="Press" IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}">
            </ToggleButton>
            <TextBox x:Name="PART_EditableTextBox" Style="{x:Null}" Template="{StaticResource ComboBoxTextBox}" Margin="3,3,23,3"
                        Focusable="True" Background="Transparent" Visibility="Hidden" IsReadOnly="{TemplateBinding IsReadOnly}"/>
            <ContentPresenter Name="ContentSite" IsHitTestVisible="False" Content="{TemplateBinding SelectionBoxItem}" Margin="3,3,23,3"
                                ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" VerticalAlignment="Center"
                                ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" HorizontalAlignment="Center" />
            <Popup Name="Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" Focusable="False" PopupAnimation="Slide">
                <Grid Name="DropDown" SnapsToDevicePixels="True" MinWidth="{TemplateBinding ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}">
                    <Border x:Name="DropDownBorder" Background="White" BorderThickness="1" BorderBrush="Black"/>
                    <ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
                        <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
                    </ScrollViewer>
                </Grid>
            </Popup>
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="HasItems" Value="False">
                <Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
            </Trigger>
            <Trigger Property="IsGrouping" Value="True">
                <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
            </Trigger>
            <Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="True">
                <Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
                <Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
            </Trigger>
            <Trigger Property="IsEditable" Value="True">
                <Setter Property="IsTabStop" Value="False"/>
                <Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
                <Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>