如何使用 WPF 按钮的参数或绑定来更改 XAML 样式中的 fa 图标

Posted

技术标签:

【中文标题】如何使用 WPF 按钮的参数或绑定来更改 XAML 样式中的 fa 图标【英文标题】:How to use parameters or binding for WPF buttons to change fa icons in XAML styles 【发布时间】:2022-01-11 01:10:38 【问题描述】:

我为 WPF 中的按钮创建了 XAML 样式,以用于菜单项。创建菜单列表时,我想根据我放入代码中的参数更改图标(FontAwesome 图标),以保持其清洁并为按钮中的其他元素使用相同的样式。

但是到目前为止,我发现无法将参数发送到样式。所以我想知道如何实现它。我也试过 Icon="Binding Path=Icon" 但我相信这并不适用于单独的每个按钮。

我有什么: All icons are the same

<Button DockPanel.Dock="Top" x:Name="MenuHome" Style="StaticResource MenuItem">Home</Button>

我想要什么: All icons are different

<Button DockPanel.Dock="Top" x:Name="MenuHome" Style="StaticResource MenuItem" Icon="Home" IconColor="Green">Home</Button>

代码:

    <!-- Menu item button style unclicked -->
    <Style x:Key="MenuItem" TargetType="x:Type Button">
        <Setter Property="Height" Value="50"/>
        <Setter Property="Background" Value="#FF33334C"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="x:Type Button">
                    <Grid>
                        <Border Background="TemplateBinding Background"/>
                        <Grid Name="GridMouseOver" Background="Black" Opacity="0.2" Visibility="Hidden"/>
                        <fa:ImageAwesome Icon="AddressBook" Height="30" Width="30" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="15,0,0,0"/>
                        <TextBlock Text="TemplateBinding Content" Foreground="Gainsboro" FontSize="20" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="60,0,0,0"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="GridMouseOver" Property="Visibility" Value="Visible"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>

            </Setter.Value>
        </Setter>
    </Style>
    
    <!-- Sub menu item button style -->
    <Style x:Key="SubMenuItem" TargetType="x:Type Button">
        <Setter Property="Height" Value="50"/>
        <Setter Property="Background" Value="#FF33334C"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="x:Type Button">
                    <Grid>
                        <Border Background="TemplateBinding Background"/>
                        <Grid Name="GridMouseOver" Background="Black" Opacity="0.2" Visibility="Hidden"/>
                        <fa:ImageAwesome Icon="Binding Path=Icon" Height="20" Width="20" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="20,0,0,0"/>
                        <TextBlock Text="TemplateBinding Content" Foreground="Gainsboro" FontSize="16" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="60,0,0,0"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="GridMouseOver" Property="Visibility" Value="Visible"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>


<!-- Button creation code -->
<Grid>
    <DockPanel>
        <!-- Menu grid -->
        <Grid x:Name="Menu" DockPanel.Dock="Left" Background="#FF33334C">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="200"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition  Height="100"/>
                <RowDefinition  Height="1*"/>
            </Grid.RowDefinitions>
            <DockPanel Grid.Row="2" LastChildFill="False">
                <Button DockPanel.Dock="Top" x:Name="MenuHome" Style="StaticResource MenuItem">Home</Button>
                <!-- Add visibility Visibility="Collapsed" to the sub menu dock panel-->
                <DockPanel x:Name="SubMenuHome" DockPanel.Dock="Top">
                    <Button DockPanel.Dock="Top" x:Name="SubMenuHome1" Style="StaticResource SubMenuItem">Sub Home 1</Button>
                    <Button DockPanel.Dock="Top" x:Name="SubMenuHome2" Style="StaticResource SubMenuItem">Sub Home 2</Button>
                </DockPanel>
                <Button DockPanel.Dock="Top" x:Name="MenuProject" Style="StaticResource MenuItem">Project</Button>
                <Button DockPanel.Dock="Top" x:Name="MenuTools" Style="StaticResource MenuItem">Tools</Button>
            </DockPanel>
        </Grid>
        <Grid x:Name="TitleBar" DockPanel.Dock="Top" Background="#FF33334C">
            <Grid.RowDefinitions>
                <RowDefinition Height="50"/>
            </Grid.RowDefinitions>
        </Grid>
        <Grid x:Name="ChildForm" Background="#FF333346">

        </Grid>
    </DockPanel>

</Grid>

【问题讨论】:

对不起,发布的代码有点乱,需要重新组织。无论如何,默认的Button 控件没有IconIconColor 属性,因此您必须使用附加属性或扩展标准Button 来添加这些属性。此外,用于按钮的模板也可以简化,因为Border 可以是直接容器并包括一个水平的StackPanel,它同时承载fa:ImageAwesomeTextBlock(或ContentPresenter)。一旦你实现了IconIconColor,那么它们就可以绑定到fa:ImageAwesomeIconForeground)。 我是 WPF 和 XAML 的新手,所以我边走边学。实际上,我对您的评论笑得很开心,因为我很高兴它正在发挥作用并且有点自豪。但显然,对于更有经验的程序员来说,这很糟糕。我肯定会在不久的将来尝试实现附加属性,因为我现在知道继续搜索的术语。我已经将边框内容更改为堆栈面板。感谢您的提示。 不要误会我的意思,但是干净的代码总是更容易调试并且性能更好。您的代码已经是一个良好的开端并且朝着正确的方向前进 :) 如果您为缺少的属性实现了某些东西(以防接受的答案不符合您的需求)并且仍然需要图标方面的帮助,只需使用您的更改更新您的问题。 【参考方案1】:

您可以尝试参考以下代码将 Icon 绑定到 Button 的 Tag 内容。包含两个方法,可以参考here。

<Style x:Key="FontAwesome">
        <Setter Property="TextElement.FontFamily" Value="pack://application:,,,/Font/#Font Awesome 5 Free Regular" />
    </Style>
    <Style x:Key="MenuItem" TargetType="x:Type Button">
        <Setter Property="Height" Value="50"/>
        <Setter Property="Background" Value="#FF33334C"/>
        <Setter Property="TextElement.FontFamily" Value="pack://application:,,,/Font/#Font Awesome 5 Free Regular" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="x:Type Button">
                    <Grid>
                        <Border Background="TemplateBinding Background"/>
                        <Grid Name="GridMouseOver" Background="Black" Opacity="0.2" Visibility="Hidden"/>
                        <fa:ImageAwesome Icon="Binding Tag, RelativeSource=RelativeSource FindAncestor,  AncestorType=Button " Height="30" Width="30" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="15,0,0,0"/>
                        <TextBlock Text="TemplateBinding Content" Foreground="Gainsboro" FontSize="20" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="60,0,0,0"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="GridMouseOver" Property="Visibility" Value="Visible"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>

            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="MenuItem2" TargetType="x:Type Button">
        <Setter Property="Height" Value="50"/>
        <Setter Property="Background" Value="#FF33334C"/>
        <Setter Property="TextElement.FontFamily" Value="pack://application:,,,/Font/#Font Awesome 5 Free Regular" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="x:Type Button">
                    <Grid>
                        <Border Background="TemplateBinding Background"/>
                        <Grid Name="GridMouseOver" Background="Black" Opacity="0.2" Visibility="Hidden"/>
                        <TextBlock Text="Binding Tag, RelativeSource=RelativeSource FindAncestor,  AncestorType=Button " FontSize="22" Margin="14" HorizontalAlignment="Left" VerticalAlignment="Center" Style="DynamicResource  FontAwesome" />
                        <TextBlock Text="TemplateBinding Content" Foreground="Gainsboro" FontSize="20" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="60,0,0,0"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="GridMouseOver" Property="Visibility" Value="Visible"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>

            </Setter.Value>
        </Setter>
    </Style>

<Grid x:Name="Menu" DockPanel.Dock="Left" Background="#FF33334C">
               ...
               <DockPanel Grid.Row="2" LastChildFill="False">
                <Button DockPanel.Dock="Top" x:Name="MenuHome" Style="StaticResource MenuItem" Tag="home">Home</Button>
                <DockPanel x:Name="SubMenuHome" DockPanel.Dock="Top" >
                    <Button DockPanel.Dock="Top" x:Name="SubMenuHome1" Style="StaticResource SubMenuItem">Sub Home 1</Button>
                    <Button DockPanel.Dock="Top" x:Name="SubMenuHome2" Style="StaticResource SubMenuItem">Sub Home 2</Button>
                </DockPanel>
                <Button DockPanel.Dock="Top" x:Name="MenuProject" Style="StaticResource MenuItem2"  Tag="&#xf542;">Project
                </Button>
            </DockPanel>
            </Grid>

结果:

【讨论】:

谢谢。它确实做到了我想要实现的目标。当我使用 Fontawesome.wpf 时,我不得不将 fontfamily 替换为“pack://application:,,,/FontAwesome.WPF;component/#FontAwesome”。但是我注意到并非所有图标都可用于此,所以接下来我将尝试使用您的完整包。您知道建议的使用 Tag 的解决方案是否是常用的解决方案?我觉得如果我将来可能想使用 Tag,这将不再可能。绑定标签可以更改为 Khiro 建议的自定义参数吗?非常感谢您的明确回答。这对我帮助很大。【参考方案2】:

下面是我如何在上面的答案/信息的帮助下改进我的代码。

我实现了 FontAwesome 5 而不是 Nuget 包 FontAwesome.WPF,因为它包含更多图标。

    从网站下载资源文件

    Download Link FA5 Desktop

    在您的项目中创建一个名为 Fonts 的文件夹 (ProjectName.csproj)

    文件夹必须处于此级别,因为首先创建多个文件夹结构 (Fonts/otf/FA5.otf) 对我不起作用。

    如果您愿意,可以将其重命名为更易于键入的名称

    FaFreeSolid 适合我

    复制到字体文件夹

    将其添加到项目中

    项目菜单 -> 显示所有文件 -> 解决方案资源管理器 -> 右键单击​​ .otf 文件 -> 添加到项目

    在 Windows 中打开 .otf 字体文件并检查顶部的名称。暂时复制一下

    创建资源字典

    RMB ProjectName.csproj -> 添加 -> ResourceDictionary (WPF) -> 命名为 FontAwesomeResources

    打开文件并创建一个 FontFamily

    第 1 部分:Key=name 来调用它

    第 2 部分:字体文件的路径

    第 3 部分:第 6 点的#FontName

代码:

<FontFamily x:Key="FaFreeSolid">/Fonts/FaFreeSolid.otf#Font Awesome 5 Free</FontFamily>
    转到 App.xaml 调用整个项目的资源

代码:

    <Application.Resources>
            <ResourceDictionary Source="FontAwesomeResources.xaml"/>  
    </Application.Resources>

    我将文本块中的资源用于 Text 属性。然后此属性设置图标图像。文字应与网站上的相同。我注意到名称中带有 - 的名称不起作用,因此您必须在文本中使用 前缀并使用其后面的图标代码编号。 (例如: = 地址簿)

    FA Cheat Sheet

这部分使“主页”图标出现:

<TextBlock Text="Home" Foreground="DarkRed" FontFamily="StaticResource FaFreeSolid" FontSize="30" VerticalAlignment="Center" Margin="15,0,0,0"/>

MainWindow.xaml:

<!-- Menu item button style unclicked -->
    <Style x:Key="btnMenuItem" TargetType="x:Type Button">
        <Setter Property="Height" Value="50"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="x:Type Button">
                    <Border Background="TemplateBinding Background">
                        <StackPanel Orientation="Horizontal">
                            <Grid Name="GridMouseOver" Background="Black" Opacity="0.2" Visibility="Hidden"/>
                            <TextBlock Text="Home" Foreground="DarkRed" FontFamily="StaticResource FaFreeSolid" FontSize="30" VerticalAlignment="Center" Margin="15,0,0,0"/>
                            <TextBlock Text="TemplateBinding Content" Foreground="Gainsboro" FontSize="20" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="20,0,0,0"/>
                        </StackPanel>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="GridMouseOver" Property="Visibility" Value="Visible"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

我要解决的下一个问题是创建一个依赖属性,以便在基于此样式创建按钮时通过属性设置图标图像和图标颜色。

【讨论】:

以上是关于如何使用 WPF 按钮的参数或绑定来更改 XAML 样式中的 fa 图标的主要内容,如果未能解决你的问题,请参考以下文章

WPF 点击按钮时更改按钮样式界面效果的 XAML 实现方法

页面框架内的WPF按钮导航以更改父页面

WPF如何更改xaml代码里ListBox的数据绑定

wpf 带参数的用户控件,如何在xaml中引入

wpf中用户控件更改期间的动画

如何以通用方式更改按钮的圆度