如何使用 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
控件没有Icon
和IconColor
属性,因此您必须使用附加属性或扩展标准Button
来添加这些属性。此外,用于按钮的模板也可以简化,因为Border
可以是直接容器并包括一个水平的StackPanel
,它同时承载fa:ImageAwesome
和TextBlock
(或ContentPresenter
)。一旦你实现了Icon
和IconColor
,那么它们就可以绑定到fa:ImageAwesome
(Icon
和Foreground
)。
我是 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="">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 图标的主要内容,如果未能解决你的问题,请参考以下文章