Search code examples
wpfxamlcontroltemplate

How to set WPF Button TextBlock style from another resource?


I'm setting in a WPF application the style of a button with this:

<Style TargetType="{x:Type Button}">
    <Setter Property="ToolTipService.InitialShowDelay" Value="0"/>
    <Setter Property="Height" Value="22" />
    <Setter Property="Margin" Value="1" />
    <Setter Property="Padding" Value="0" />
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        Padding="{TemplateBinding Padding}"
                        BorderThickness="1">
                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="1 -1 1 0"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Background" Value="{StaticResource NotSelectedButton}" />
    <Setter Property="Foreground" Value="{StaticResource ActiveFg}" />
    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Background" Value="{StaticResource Selected}" />
            <Setter Property="Foreground" Value="{StaticResource SelectedFg}" />
        </Trigger>
        <Trigger Property="IsMouseOver" Value="False">
            <Setter Property="Background" Value="{StaticResource NotSelectedButton}" />
            <Setter Property="Foreground" Value="{StaticResource ActiveFg}" />
        </Trigger>
        <Trigger Property="IsEnabled" Value="False">
            <Setter Property="Background" Value="{StaticResource NotSelectedButton}" />
            <Setter Property="Foreground" Value="{StaticResource InactiveFg}" />
            <!--<Setter Property="Foreground" Value="{StaticResource NotSelected}" />-->
        </Trigger>
    </Style.Triggers>
</Style>

However I want the TextBlock in the ContentPresenter to use a named TextBlock style defined as such:

<Style x:Key="ButtonText" TargetType="{x:Type TextBlock}">
    <Setter Property="ToolTipService.InitialShowDelay" Value="0"/>
    <Setter Property="Width" Value="auto" />
    <Setter Property="MinWidth" Value="20" />
    <Setter Property="TextAlignment" Value="Left" />
    <Setter Property="Padding" Value="0 0 0 0" />
    <Setter Property="Margin" Value="1 0 0 0" />
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="HorizontalAlignment" Value="Center" />
</Style>

To test this style, just a Button in a UserControl or Window suffices: <Button>, and the style definitions can go in a resource dictionary (of UserControl or Window).

How can I do this ?


Solution

  • Trivial Solution via Direct Assignment

    You can set the style directly by assigning a TextBlock as Content of each Button.

    <Button>
       <TextBlock Text="Test" Style="{StaticResource ButtonText}"/>
    </Button>
    

    Support Text As Content Only

    If you are sure that you only put strings as content into your button, you can assign a ContentTemplate that contains a TextBlock to the ContentPresenter. This will not work for other content types in the sense that it would not display them as usual, but just their type name in the TextBlock.

    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="1 -1 1 0">
       <ContentPresenter.ContentTemplate>
          <DataTemplate>
             <TextBlock Style="{StaticResource ButtonText}" Text="{Binding}"/>
          </DataTemplate>
       </ContentPresenter.ContentTemplate>
    </ContentPresenter>
    

    Support All Content Types

    If you want to support any content type as content of your button, you can define the data template from above in the ContentPresenter.Resources. Then, the ContentPresenter will only apply it, if the Content is a string. For all other content types it will work as usual.

    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="1 -1 1 0">
       <ContentPresenter.Resources>
          <DataTemplate DataType="{x:Type system:String}">
             <TextBlock Style="{StaticResource ButtonText}" Text="{Binding}"/>
          </DataTemplate>
       </ContentPresenter.Resources>
    </ContentPresenter>