【问题标题】:How to use parameters or binding for WPF buttons to change fa icons in XAML styles如何使用 WPF 按钮的参数或绑定来更改 XAML 样式中的 fa 图标
【发布时间】: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 的新手,所以我边走边学。实际上,我对您的评论笑得很开心,因为我很高兴它正在发挥作用并且有点自豪。但显然,对于更有经验的程序员来说,这很糟糕。我肯定会在不久的将来尝试实现附加属性,因为我现在知道继续搜索的术语。我已经将边框内容更改为堆栈面板。感谢您的提示。
  • 不要误会我的意思,但是干净的代码总是更容易调试并且性能更好。您的代码已经是一个良好的开端并且朝着正确的方向前进 :) 如果您为缺少的属性实现了某些东西(以防接受的答案不符合您的需求)并且仍然需要图标方面的帮助,只需使用您的更改更新您的问题。

标签: c# wpf visual-studio font-awesome


【解决方案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,因为它包含更多图标。

  1. 从网站下载资源文件

    Download Link FA5 Desktop

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

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

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

    FaFreeSolid 适合我

  4. 复制到字体文件夹

  5. 将其添加到项目中

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

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

  7. 创建资源字典

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

  8. 打开文件并创建一个 FontFamily

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

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

    第 3 部分:第 6 点的#FontName

代码:

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

代码:

    <Application.Resources>
            <ResourceDictionary Source="FontAwesomeResources.xaml"/>  
    </Application.Resources>
  1. 我将文本块中的资源用于 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>

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-19
    • 1970-01-01
    • 1970-01-01
    • 2014-07-15
    • 1970-01-01
    • 2015-02-04
    • 2017-10-02
    • 2021-01-21
    相关资源
    最近更新 更多