1
votes

I am trying to find a solution to reuse code in XAML for in WPF: I have 3 buttons that have very similar styles, with the only difference being the BorderThickness. They all have a style trigger set that if the user moves the mouse over them, the BorderThickness is set to 1.

<Button Width="50" Height="50" BorderBrush="#66CCFF" >
  <Button.Style>
    <Style TargetType="{x:Type Button}">
      <Setter Property="BorderThickness" Value="0,0,0,1" />
      <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="BorderThickness" Value="1"/>
        </Trigger>
      </Style.Triggers>
      </Style>
  </Button.Style>
  <Image Margin="12" Source="picture1.png"/>
</Button>

<Button Width="50" Height="50" BorderBrush="#66CCFF">
  <Button.Style>
    <Style TargetType="{x:Type Button}">
      <Setter Property="BorderThickness" Value="0,1,0,1" />
      <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="BorderThickness" Value="1"/>
        </Trigger>
      </Style.Triggers>
      </Style>
  </Button.Style>
  <Image Margin="12" Source="picture2.png"/>
</Button>

<Button Width="50" Height="50"BorderBrush="#66CCFF">
  <Button.Style>
    <Style TargetType="{x:Type Button}">
      <Setter Property="BorderThickness" Value="1,0,1,1" />
      <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="BorderThickness" Value="1"/>
        </Trigger>
      </Style.Triggers>
    </Style>
  </Button.Style>
  <Image Margin="12" Source="picture3.png"/>
</Button>

Since the styles are practically identical apart from the BorderThickness that is applied when the IsMouseOver is false I would like to remove code duplicates and have some sort of Style in a ResourceDictionary where I can specify the initial BorderThickness as a parameter (or something along the lines) and the rest is the same.

I tried to move the BorderThickness="p,q,r,s" part to the <Button ...> tag, but then the style does not get applied when I mouse over (my assumption is that there's a hierarchy between them).

2
Hi, I think this is covered in a lot of online tutorials about styling in wfp. - Stefan
@Stefan I am aware of how styles are used in general, but not when it comes to having slightly different ones. I wouldn't want to maintain similar code in 3 places. There is a difference between the 3 Styles, but only a very small one, which could be parameterized - if there is an option for this. - ZekeMarsh
So the in the article mentioned Style inheritance is not sufficient? - Stefan
@Stefan it could be sufficient, but with that I can only move out the <Style.Triggers> part, not the full <Style>. Maybe what I am asking (parameterized style) is not possible, I just want to make sure. Or if my understanding is wrong, let me know. Thank you for the link though. - ZekeMarsh

2 Answers

2
votes

Not sure if this is what you are aiming for, but a common approach is to create a style definition in the app.xaml and use those styes in the template or on your page, it uses a common reused base style, reusable thicknesses (here they are only used once) and inheritance:

<Application.Resources>
    <ResourceDictionary>
        <!-- not really parameters, more like static values. -->
        <!-- these could be bind dynamically and -->
        <!-- controlled from code if you like. -->
        <!-- ps: i used different values. -->
        <Thickness x:Key="topThickness">10,0,0,0</Thickness>
        <Thickness x:Key="middleThickness">0,10,0,0</Thickness>
        <Thickness x:Key="bottomThickness">0,0,10,0</Thickness>

        <Style x:Key="buttonBase" TargetType="{x:Type Button}">
            <Setter Property="Width" Value="50" />
            <Setter Property="Height" Value="50" />
            <Setter Property="BorderBrush" Value="#66CCFF" />
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="BorderThickness" Value="1"/>
                </Trigger>
            </Style.Triggers>
        </Style>

        <Style x:Key="buttonTop" 
               BasedOn="{StaticResource buttonBase}" 
               TargetType="{x:Type Button}">
            <Setter Property="BorderThickness" 
                    Value="{StaticResource topThickness}" />
        </Style>

        <Style x:Key="buttonMiddle" 
               BasedOn="{StaticResource buttonBase}" 
               TargetType="{x:Type Button}">
            <Setter Property="BorderThickness" 
                    Value="{StaticResource middleThickness}" />
        </Style>

        <Style x:Key="buttonBottom" 
               BasedOn="{StaticResource buttonBase}" 
               TargetType="{x:Type Button}">
            <Setter Property="BorderThickness" 
                    Value="{StaticResource bottomThickness}" />
        </Style>
    </ResourceDictionary>
</Application.Resources>

And in your window: note that the actual styling is controlled in the resource dictionary

<Button Style="{StaticResource buttonTop}" >
    <Image Margin="12" Source="picture1.png"/>
</Button>
<Button Style="{StaticResource buttonMiddle}" >
   <Image Margin="12" Source="picture1.png"/>
</Button>
<Button Style="{StaticResource buttonBottom}" >
    <Image Margin="12" Source="picture1.png"/>
</Button>
0
votes

You can use animation since it has higher priority than local value: https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-property-value-precedence

<Style TargetType="Button">
    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Trigger.EnterActions>
                <BeginStoryboard x:Name="BorderAnimation">
                    <Storyboard TargetProperty="BorderThickness">
                        <ThicknessAnimation To="1" Duration="0"/>
                    </Storyboard>
                </BeginStoryboard>
            </Trigger.EnterActions>
            <Trigger.ExitActions>
                <RemoveStoryboard BeginStoryboardName="BorderAnimation"/>
            </Trigger.ExitActions>
        </Trigger>
    </Style.Triggers>
</Style>

<UniformGrid Columns="2" Rows="2" Width="100" Height="100">
    <Button BorderThickness="1 1 0 0"/>
    <Button BorderThickness="0 1 1 0"/>
    <Button BorderThickness="1 0 0 1"/>
    <Button BorderThickness="0 0 1 1"/>
</UniformGrid>