Search code examples
c#wpfxamlcombobox

Scale Arrow Size for ComboBox in WPF


I have a wpf app that runs in windows IoT with a touch screen. I have some screens with combo boxes which allow the user to press it and select an item and save it. The Combo boxes are put into a uniform grid so the combo box is quite large (for touch screen fingers). Everything seems to scale fine (text, dropdown items, the button), except the arrow. The graphic down arrow seems to always be the same size no matter what size the combo box is.

My question is, how can I scale the down arrow to scale with the size of the combo box?

Image of Down Arrow

My current combo box code:

<UniformGrid Grid.Row="1" Columns="2" Rows="5">
<Label Content="{x:Static properties:Resources.UnitsSettings_Pressure}"/>
<ComboBox ItemsSource="{Binding Source={helpers:EnumBindingSource {x:Type settings:PRESSURE_UNITS}}}" SelectedItem="{Binding PressureUnits}"
          MaxDropDownHeight="600" 
          BorderBrush="#FF46AA2D" 
          BorderThickness="4" 
          Background="White" 
          Foreground="Black" 
          FontFamily="Microsoft Sans Serif" 
          FontSize="36" 
          HorizontalContentAlignment="Center" 
          VerticalContentAlignment="Center" 
          VerticalAlignment="Stretch" 
          HorizontalAlignment="Stretch" 
          Focusable="False"
          Margin="2"
          ScrollViewer.PanningMode="VerticalOnly"
          ScrollViewer.PanningDeceleration="0.001"
          ScrollViewer.PanningRatio="1">
</ComboBox>

Looks like this: Combo Box as is Combo Box as is pressed

What I've tried: I tried messing with the LayoutTransform and the ScaleTransform but it results in the whole combobox getting scaled and I just want to scale the down arrow icon.

My scale code:

<UniformGrid Grid.Row="1" Columns="2" Rows="5">
<Label Content="{x:Static properties:Resources.UnitsSettings_Pressure}"/>
<ComboBox ItemsSource="{Binding Source={helpers:EnumBindingSource {x:Type settings:PRESSURE_UNITS}}}" SelectedItem="{Binding PressureUnits}"
          MaxDropDownHeight="600" 
          BorderBrush="#FF46AA2D" 
          BorderThickness="4" 
          Background="White" 
          Foreground="Black" 
          FontFamily="Microsoft Sans Serif" 
          FontSize="36" 
          HorizontalContentAlignment="Center" 
          VerticalContentAlignment="Center" 
          VerticalAlignment="Stretch" 
          HorizontalAlignment="Stretch" 
          Focusable="False"
          Margin="2"
          ScrollViewer.PanningMode="VerticalOnly"
          ScrollViewer.PanningDeceleration="0.001"
          ScrollViewer.PanningRatio="1">
          
        <ComboBox.Resources>
            <Style TargetType="ComboBox">
                <Setter Property="LayoutTransform">
                    <Setter.Value>
                        <ScaleTransform ScaleX="2.0" ScaleY="2"/>
                    </Setter.Value>
                </Setter>
            </Style>
        </ComboBox.Resources>
</ComboBox>

What it looks like: Combo Box Scaled Combo Box Scaled clicked


Solution

  • Your have to change default Style of ComboBox to achieve your goal. Right click the ComboBox in xaml designer of VS, select 'Edit Template'->'Edit a Copy', the built in Style of ComboBox will be added to your xaml code. Search for:

    <Border x:Name="templateRoot" Background="{StaticResource ComboBox.Static.Background}" BorderBrush="{StaticResource ComboBox.Static.Border}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
    <Border x:Name="splitBorder" BorderBrush="Transparent" BorderThickness="1" HorizontalAlignment="Right" Margin="0" SnapsToDevicePixels="true" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}">
        <Path x:Name="arrow" Data="F1 M 0,0 L 2.667,2.66665 L 5.3334,0 L 5.3334,-1.78168 L 2.6667,0.88501 L0,-1.78168 L0,0 Z" Fill="{StaticResource ComboBox.Static.Glyph}" HorizontalAlignment="Center" Margin="0" VerticalAlignment="Center"/>
    </Border>
    

    Then replace it with:

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="0.125*"/>
        </Grid.ColumnDefinitions>
        <Border x:Name="templateRoot" Background="{StaticResource ComboBox.Static.Background}" BorderBrush="{StaticResource ComboBox.Static.Border}"
                BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true" Grid.ColumnSpan="2"/>
        <Border x:Name="splitBorder" BorderBrush="Transparent" BorderThickness="1" HorizontalAlignment="Stretch" Margin="0" SnapsToDevicePixels="true"
                MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Grid.Column="1">
            <Path x:Name="arrow" Data="F1 M 0,0 L 2.667,2.66665 L 5.3334,0 L 5.3334,-1.78168 L 2.6667,0.88501 L0,-1.78168 L0,0 Z" Fill="{StaticResource ComboBox.Static.Glyph}"
                  Margin="5" Stretch="Uniform"/>
        </Border>
    </Grid>
    

    You can change the ratio of two ColumnDefinition.Width to adjust how much space the arrow will take. You also can change Path.Margin to adjust final size of the arrow to fill your need. And all other behaviors will remain the same as the original. This answer is base on .net 8.0. The other versions may have different Style for ComboBox, but the concept is the same.