使用Setter方式设置样式内容 v 内容模板

7
第一种样式的XAML可以满足要求,使用setter来布局内容及其属性,生成一个带有Wingding字形的按钮。第二个版本的样式尝试使用DataTemplate来设置Content,但只显示DataTemplate的类型(即System.Windows.DataTemplate)。
1. 为什么第二个版本不能显示与第一个版本相同的内容?
2. 假设修复问题很简单,那么除了个人喜好之外,是否有其他原因更倾向于使用其中一个版本的样式?
注意:我展示绑定和触发器,以防这些内容影响到内容,但只有第一部分的样式会变化。
样式1
显示:enter image description here
<Style x:Key="EditCommandButtonStyle" TargetType="{x:Type Button}" >
    <Setter Property="Content" Value="a" />
    <Setter Property="Foreground" Value="Navy" />
    <Setter Property="FontFamily" Value="Wingdings 3" />
    <Setter Property="FontWeight" Value="Bold" />
    <Setter Property="FontSize" Value="18" />
    <Setter Property="Width" Value="30" />
    <Setter Property="Height" Value="Auto" />

    <!--What makes it an Edit button-->
    <Setter Property="Command" Value="{Binding ActivateThisSatelliteVmCommand}"/>
    <Setter Property="ToolTip">
        <Setter.Value>
            <TextBlock>
                <TextBlock.Text>
                    <Binding Path="HeaderLabel" StringFormat="{resx:Resx ResxName=Smack.Core.Presentation.Resources.MasterDetail, Key=Item_Edit_Label}"/>
                </TextBlock.Text>
            </TextBlock>
        </Setter.Value>
    </Setter>

    <!-- WHen its available -->
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border x:Name="theBorder" CornerRadius="4">
                    <ContentPresenter x:Name="theContent" VerticalAlignment="Center" HorizontalAlignment="Center" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="False">
                        <Setter TargetName="theContent" Property="Visibility" Value="Hidden"/>
                        <Setter TargetName="theBorder" Property="Background" Value="Transparent"/>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="theContent" Property="Visibility" Value="Visible"/>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter TargetName="theContent" Property="Visibility" Value="Visible"/>
                        <Setter TargetName="theBorder" Property="Background" Value="Orange"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

样式2

显示“System.Windows.DataTemplate”

<Style x:Key="EditCommandButtonStyle" TargetType="{x:Type Button}" >
    <Setter Property="Content">
        <Setter.Value>
            <DataTemplate>
                <TextBlock Text="a" FontFamily="Wingdings 3" FontWeight="Bold" FontSize="18" Foreground="Navy" />
            </DataTemplate>
        </Setter.Value>
    </Setter>

    <!--What makes it an Edit button-->
    <Setter Property="Command" Value="{Binding ActivateThisSatelliteVmCommand}"/>
    <Setter Property="ToolTip">
        <Setter.Value>
            <TextBlock>
                <TextBlock.Text>
                    <Binding Path="HeaderLabel" StringFormat="{resx:Resx ResxName=Core.Presentation.Resources.MasterDetail, Key=Item_Edit_Label}"/>
                </TextBlock.Text>
            </TextBlock>
        </Setter.Value>
    </Setter>

    <!-- When its available -->
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border x:Name="theBorder" CornerRadius="4">
                    <ContentPresenter x:Name="theContent" VerticalAlignment="Center" HorizontalAlignment="Center" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="False">
                        <Setter TargetName="theContent" Property="Visibility" Value="Hidden"/>
                        <Setter TargetName="theBorder" Property="Background" Value="Transparent"/>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="theContent" Property="Visibility" Value="Visible"/>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter TargetName="theContent" Property="Visibility" Value="Visible"/>
                        <Setter TargetName="theBorder" Property="Background" Value="Orange"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

将TextBlock中的包装DataTemplate移除是否解决了问题? - LPL
1
@LPL。不,没有DataTemplate的包装,它会导致运行时错误:Error 1 'System.Windows.Controls.TextBlock' 不是 Setter 的 'System.Windows.Controls.ContentControl.ContentTemplate' 属性的有效值。 - Berryl
1
删除DataTemplate对我来说有效。您只需将内容放入content属性中即可,无需模板。 - Phil
@Phil。当您尝试将该样式与多个父级一起使用时,这将导致不同的问题。请参阅Rachel的博客文章以获取详细信息 - Berryl
2个回答

18

您的Content属性设置为DataTemplate

DataTemplate应该与Template属性一起使用,而不是通过Content属性直接插入VisualTree。

将样式Setter更改为设置ContentTemplate而不是Content,它应该可以正常工作。

<Setter Property="ContentTemplate">
    <Setter.Value>
        <DataTemplate>
            <TextBlock Text="a" FontFamily="Wingdings 3" FontWeight="Bold" FontSize="18" Foreground="Navy" />
        </DataTemplate>
    </Setter.Value>
</Setter>

至于您的第二个问题,我更喜欢第一个方案,因为它更简单,而且我认为可能在可视树中包含的元素更少(我需要再确认一下)。


10
毫不意外,Bingo。这证实了我的猜想——当只有极少数人能够回答本应是琐碎问题时,WPF的学习曲线异常陡峭。干杯。 - Berryl
1
我还需要在我的父模板中使用<ContentPresenter />而不是<ContentControl Content="{TemplateBinding Content}" />才能使它工作,但现在我无法覆盖视图中的内容了。这使得它不再是可重写的默认值。(这是我的最初目标) - jeromej

0
我找到了另一种解决这个问题的方法:
<Style x:Key="DefaultButtonBaseStyle" TargetType="{x:Type ButtonBase}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ButtonBase}">
                <Grid>
                    <Border x:Name="BackBorder" Margin="0" Padding="0"
                            BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding BorderBrush}"/>
                    <Border x:Name="FrontBorder" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}"
                            Margin="0" Padding="{TemplateBinding Padding}"
                            CornerRadius="{Binding ElementName=BackBorder, Path=CornerRadius}">
                        <ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接