Search code examples
c#wpfdata-bindingmahapps.metro

WPF binding mahapps metro icons in template - Tag binding not working


I have a navbar with several buttons in it. The buttons all use the same style, defined in a ResourceDictionary.

I am trying to add an icon from Mahapps to each button. Each button will need a different kind of icon, which I'd like to set on the view.

In order to achieve this, I need to be able to pass the icon kind to the template via some property of the button.

I am unable to pass the icon kind to the template.

I am testing this on a new project (WPF netcore3.1)

I have seen other posts (post1, post2) that suggest using a rectangle rather than iconPacks, and binding the Visual property of the rectangle using the Tag property of the button:

<Application x:Class="WpfApp1.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:WpfApp1"
         StartupUri="MainWindow.xaml">
<Application.Resources>
    <ResourceDictionary Source="/IconStyle.xaml" />
</Application.Resources>
<Window x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"   
    xmlns:local="clr-namespace:WpfApp1"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<StackPanel>
    <Button Style="{StaticResource IconStyle}" Foreground="Red">
        <Button.Tag>
            <iconPacks:Modern Kind="Home" Width="24" Height="24" />
        </Button.Tag>
    </Button>
</StackPanel>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:local="clr-namespace:WpfApp1">
<Style x:Key="IconStyle" TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <StackPanel Orientation="Horizontal"
                        DataContext="{Binding RelativeSource={RelativeSource AncestorType=Button}}">
                    <Rectangle Width="24" Height="24" Fill="{Binding Foreground}">
                        <Rectangle.OpacityMask>
                            <VisualBrush Stretch="Fill" Visual="{Binding Tag}" />
                        </Rectangle.OpacityMask>
                    </Rectangle>
                    <TextBlock Margin="10 0 10 0" VerticalAlignment="Center" Text="John Doe" 
                           FontSize="24" FontWeight="Normal" FontFamily="Segoe UI Light" />
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

But doesn't display any icons at all for me.

Any suggestions?


Solution

  • With the IconPacks you don't need the OpacityMask usage. Instead you can work with the PackIconModern control or any other control from the IconPacks package.

    Here is an example with only the PackIconModern control from the MahApps.Metro.IconPacks.Modern NuGet package (v4.11.0).

    The button style:

    <Style x:Key="IconStyle" TargetType="{x:Type Button}">
        <Setter Property="Padding" Value="10 5" />
        <Setter Property="HorizontalContentAlignment" Value="Left" />
        <Setter Property="FontSize" Value="24" />
        <Setter Property="FontWeight" Value="Normal" />
        <Setter Property="FontFamily" Value="Segoe UI Light" />
        <Setter Property="ContentTemplate">
            <Setter.Value>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <iconPacks:PackIconModern
                            Kind="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}, Path=Tag, Mode=OneWay}"
                            Width="24"
                            Height="24"
                            VerticalAlignment="Center" />
    
                        <TextBlock Margin="10 0 0 0"
                                   VerticalAlignment="Center"
                                   Text="{Binding}" />
                    </StackPanel>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    With that style you can the do something like that:

    <Grid>
    
        <StackPanel Orientation="Vertical" VerticalAlignment="Center" Margin="5 10">
            <Button Style="{StaticResource IconStyle}"
                    Foreground="Crimson"
                    Content="John Doe"
                    Tag="{x:Static iconPacks:PackIconModernKind.Home}" />
            <Button Style="{StaticResource IconStyle}"
                    Foreground="ForestGreen"
                    Content="Works..."
                    Tag="{x:Static iconPacks:PackIconModernKind.Cloud}" />
        </StackPanel>
    
    </Grid>
    

    The namespace for the IconPacks control is xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks".

    If you need more icons from another package the simply add the NuGet package and use this control then. It's also possible to use the main IconPacks package which contains all icon controls and a control which can handle all possible icon kind enumerations. You will find more information at the wiki of the repository ion GitHub (MahApps.Metro.IconPacks).

    enter image description here