具有多个文本块的 XAML 样式按钮

本文关键字:XAML 样式 按钮 文本 | 更新日期: 2023-09-27 18:32:59

我设计了一个包含两个TextBlockButton元素。一个带有实际文本,另一个带有图标(来自Segoe UI符号)。

这是样式的代码:

<Style x:Key="ButtonSettingsStyle" TargetType="Button">
    <Setter Property="Content" Value=""/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Foreground" Value="White"/>
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="Button">
          <StackPanel Background="Transparent" Orientation="Horizontal" Height="60">
            <VisualStateManager.VisualStateGroups>
              ...
            </VisualStateManager.VisualStateGroups>
            <TextBlock 
              x:Name="Icon"
              Text="&#xE115;"
              Margin="10,0,5,0" 
              Width="40"
              Foreground="{TemplateBinding Foreground}"
              FontSize="32"
              VerticalAlignment="Center"
              RenderTransformOrigin="0.5,0.5" 
              FontFamily="Segoe UI Symbol"></TextBlock>
            <TextBlock 
              x:Name="Text" 
              Text="{TemplateBinding Content}"
              VerticalAlignment="Center"
              Style="{StaticResource TextBlockListBoldItem}"
              Foreground="{TemplateBinding Foreground}" />
          </StackPanel>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>

问题:

我还希望 Icon-TextBlock 有一个自定义图标,因此是一个自定义Text属性,并且可能像这样使用(我真的不知道这应该如何工作):

<Button Style="{StaticResource ButtonSettingsStyle}" Content="Settings" IconContent="&#xE115;" />

我怎样才能做到这一点?Content -Setter 已经分配给 Text-TextBlock ...

感谢您的帮助!

具有多个文本块的 XAML 样式按钮

编辑:我同意@meilke评论,但问题是你需要一个依赖属性来设置模板绑定,所以请参阅下面的新类 ButtonWithIcon

您应该从 Button 继承并添加一个名为 IconContent 的依赖项属性:

public class ButtonWithIcon : Button
{
    public static readonly DependencyProperty IconContentProperty =
        DependencyProperty.Register("IconContent", typeof (string), typeof (ButtonWithIcon), new PropertyMetadata(default(Icon)));
    public string IconContent
    {
        get { return (string) GetValue(IconContentProperty); }
        set { SetValue(IconContentProperty, value); }
    }
}

并像这样使用它:

<Style x:Key="ButtonSettingsStyle" TargetType="local:ButtonWithIcon">
  <Setter Property="Content" Value=""/>
  <Setter Property="Background" Value="Transparent"/>
  <Setter Property="Foreground" Value="White"/>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="local:ButtonWithIcon">
        <StackPanel Background="Transparent" Orientation="Horizontal" Height="60">
          <VisualStateManager.VisualStateGroups>
            ...
          </VisualStateManager.VisualStateGroups>
          <TextBlock 
            x:Name="Icon"
            Text="{Binding IconContent, RelativeSource={RelativeSource TemplatedParent}}"
            Margin="10,0,5,0" 
            Width="40"
            Foreground="{TemplateBinding Foreground}"
            FontSize="32"
            VerticalAlignment="Center"
            RenderTransformOrigin="0.5,0.5" 
            FontFamily="Segoe UI Symbol"></TextBlock>
          <TextBlock 
            x:Name="Text" 
            Text="{TemplateBinding Content}"
            VerticalAlignment="Center"
            Style="{StaticResource TextBlockListBoldItem}"
            Foreground="{TemplateBinding Foreground}" />
        </StackPanel>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>
<local:ButtonWithIcon Style="{StaticResource ButtonSettingsStyle}" Content="Settings" IconContent="&#xE115;" />

如果不想对 Button 进行子类化以添加自己的属性,则可以使用 Tag 属性或附加属性。

请注意,如果使用附加属性,则需要绑定到TemplatedParent而不是使用 TemplateBinding

{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
         Path=local:AttachedProperties.IconContent}

我不知道你为什么要限制你的按钮只接受文本。通常,按钮接受任何内容并使用内容演示器。就个人而言,我会将 IconContent 属性键入为object并像这样定义模板:

<ContentPresenter x:Name="Icon" Content="{TemplateBinding IconContent}" />
<ContentPresenter x:Name="Text" />

然后像这样设置:

<Button>
    <Button.IconContent>
        <TextBlock Style="{StaticResource IconTextBlockStyle}" Text="&#xE115;" />
    </Button.IconContent>
</Button>

具有自定义属性的子类Button IconContent来实现这一点。

这是新类:

public class MyButton : Button
{
  public static readonly DependencyProperty IconContentProperty =
    DependencyProperty.Register("IconContent", typeof (string), typeof (ButtonWithIcon),   new PropertyMetadata(default(Icon)));
  public string IconContent
  {
    get { return (string) GetValue(IconContentProperty); }
    set { SetValue(IconContentProperty, value); }
  }
}

以下是调整后的样式(请注意IconContent的新TemplateBinding):

<Style x:Key="ButtonSettingsStyle" TargetType="local:MyButton">
  <Setter Property="Content" Value=""/>
  <Setter Property="Background" Value="Transparent"/>
  <Setter Property="Foreground" Value="White"/>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="local:MyButton">
        <StackPanel Background="Transparent" Orientation="Horizontal" Height="60">
          <VisualStateManager.VisualStateGroups>
            ...
          </VisualStateManager.VisualStateGroups>
          <TextBlock 
            x:Name="Icon"
            Text="{TemplateBinding IconContent}"
            Margin="10,0,5,0" 
            Width="40"
            Foreground="{TemplateBinding Foreground}"
            FontSize="32"
            VerticalAlignment="Center"
            RenderTransformOrigin="0.5,0.5" 
            FontFamily="Segoe UI Symbol"></TextBlock>
          <TextBlock 
            x:Name="Text" 
            Text="{TemplateBinding Content}"
            VerticalAlignment="Center"
            Style="{StaticResource TextBlockListBoldItem}"
            Foreground="{TemplateBinding Foreground}" />
        </StackPanel>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

这是用法:

<local:MyButton Style="{StaticResource ButtonSettingsStyle}" Content="Settings" IconContent="&#xE115;" />