Search code examples
wpfexpression-blendwpf-style

How to style a WPF ToggleButton like star button


appbar_star static resource is the designed star from modern-icons

StarToggleButtonStyle

<Style x:Key="StarToggleButtonStyle" TargetType="ToggleButton">
    <Setter Property="Foreground" Value="White"/>
    <Setter Property="BorderBrush" Value="Black"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ToggleButton">
                <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                    <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                      RecognizesAccessKey="True"
                                      ContentTemplate="{TemplateBinding ContentTemplate}"
                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                      Margin="{TemplateBinding Padding}"
                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                </Border>
                <ControlTemplate.Triggers>

                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Usage

<ToggleButton cal:Message.Attach="Favorite($dataContext)" Width="15" Height="15" Style="{StaticResource StarToggleButtonStyle}" Margin="10,0,0,0">
                                                                    <Rectangle Width="10" Height="10" Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ToggleButton}}}">
                                                                        <Rectangle.OpacityMask>
                                                                            <VisualBrush Stretch="Fill" Visual="{StaticResource appbar_star}" />
                                                                        </Rectangle.OpacityMask>
                                                                    </Rectangle>
                                                                </ToggleButton>

However, here is what I got from the above markup:

enter image description here

I'd like that the border follow along the content icon, and not be a square border. How to accomplish that?


Solution

  • I followed a slightly different approach, grabbed the Canvas with Path from the resource you listed and knocked up a prototype in Kaxaml using a custom ControlTemplate (I think it's the behaviour you're after):

    <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="Coral">
        <Grid >
            <Grid.Resources>
              <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Key="AppBar" x:Name="appbar_star" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
                  <Path Width="41.1667" Height="38" Canvas.Left="17.4167" Canvas.Top="18" Stretch="Fill" Fill="#FF000000" Data="F1 M 17.4167,32.25L 32.9107,32.25L 38,18L 43.0893,32.25L 58.5833,32.25L 45.6798,41.4944L 51.4583,56L 38,48.0833L 26.125,56L 30.5979,41.7104L 17.4167,32.25 Z "/>
              </Canvas>
        <!-- StarButton Template -->
                <ControlTemplate x:Key="StarToggleButton" TargetType="{x:Type ToggleButton}">
                    <Canvas
                        Width="76"
                        Height="76"
                        Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
                        <Path
                            x:Name="ButtonPath"
                            Width="41.166"
                            Height="38"
                            Canvas.Left="17.416"
                            Canvas.Top="18"
                            Data="F1 M 17.416,32.25L 32.910,32.25L 38,18L 43.089,32.25L 58.583,32.25L 45.679,41.494L 51.458,56L 38,48.083L 26.125,56L 30.597,41.710L 17.416,32.25 Z "
                            Fill="Transparent"
                            Stroke="Black"
                            StrokeThickness="2"
                            Stretch="Fill"/>
                    </Canvas>
                    <!-- When checked, fill with Yellow -->
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter TargetName="ButtonPath" Property="Fill" Value="Yellow"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Grid.Resources>
        <!-- Example Usage -->
            <Grid Background="Transparent">
                <StackPanel Height="25" Margin="5" Orientation="Horizontal">
                    <RadioButton
                        Content="All"
                        GroupName="View"
                        Padding="2"
                        Template="{DynamicResource StarToggleButton}"/>
                    <RadioButton
                        Content="All2"
                        GroupName="View"
                        Padding="2"
                        Template="{DynamicResource StarToggleButton}"/>
                </StackPanel>
            </Grid>
        </Grid>
    </Page>
    

    The important part is that we're using the StrokeThickness and Stroke properties on Path to provide the outline of the control; the Fill is transparent until the button is selected, then a trigger takes care of changing the Fill property to yellow when the button is toggled.

    Star Toggle Button

    Toggled, and Untoggled respectively.