UWP:没有 ControlTemplate 的按钮表现不同于一个

UWP: Button without ControlTemplate behaving different than with one

可能我从根本上理解了一些错误,但根据我所读的内容,ControlTemplate-属性 允许我完全定义控件的外观,而无需更改其逻辑(如事件等)。

为了进行一些测试,我创建了一个空的 UWP 项目,并创建了一个带有拉伸的按钮:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Button HorizontalAlignment="Stretch" 
            Background="Red">
    </Button>
</Grid>

不出所料,But​​ton 贯穿整个 Window。 现在,我用基本上完全相同的按钮覆盖模板,但作为模板:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Button>
        <Button.Template>
            <ControlTemplate>
                <Button HorizontalAlignment="Stretch" 
                        Background="Red" />
            </ControlTemplate>
        </Button.Template>
    </Button>
</Grid>

在这种情况下,Horizo​​ntalAlignment 将被忽略。 因为我基本上用默认按钮模板(一个按钮)覆盖了按钮的外观,所以我期望有相同的行为。我可以通过在 Button 本身上定义 Horizo​​ntalAlignment 然后使用 TemplateBinding 来修复它,但我不明白为什么它没有按预期被覆盖。

如果我们查看 Button 的默认模板,它本质上是这样的(省略了一些诸如视觉状态的内容):

<Grid>
    <ContentPresenter/>
</Grid>

检查实时可视化树中的按钮可确认:

因此您看到 Grid 没有替换 Button 元素,Button 仍然是可视化树中的一个 Button,而是模板定义了直接 child 的按钮将是。

如果您将模板设置为以下内容:

<Button HorizontalAlignment="Stretch" Background="Red"/>

然后你会得到这个视觉树:

Horizo​​ntalAlignment 无法以这种方式工作的原因是因为它应用于内部 Button 而不是外部按钮。作为布局过程的一部分,外部按钮 (parent) 决定内部按钮 (child) 的大小和位置,并且由于 parent 未拉伸, 它只能容纳显示 child.

所需的最小尺寸

这就像你正在尝试这样做:

<Grid>
    <Button>
        <!-- This button won't stretch to the width of the Grid -->
        <Button HorizontalAlignment="Stretch"/>
    <Button>
</Grid>

把一个Button的Template设置成一个Button是没有意义的。看起来你想要做的是设置一个样式,然后你可以为模板设置一个 setter 和 parent.

的 Horizo​​ntalAlignment
<Style x:Name="MyCustomButton" TargetType="Button">
    <Setter Property="HorizontalAlignment" Value="Stretch"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                ....
            </ControlTemplate>
        </Setter>
    </Setter>
</Style>

如果要调整控件的模板,可以在 XAML 设计器中右键单击它 > 编辑模板 > 编辑副本。这会将该控件的默认样式引入您的页面,然后您可以对其进行修改。


编辑

So, every Control, even without Template, has an appearance in the VisualTree and thus needs to be targeted?

我不确定您所说的 "targeted" 是什么意思,但是是的,每个控件和 Control-derived class 都有一个可以指定的模板。如果您对这些样式感兴趣,每个控件都有一个 default style which sets the Template for the control (among other properties). I refer you to Default control styles and templates

The Template then only overrides the "Content" of the Control?

没有。显示内容的 ContentControl (such as a Button) is different from the Template. Think of the Template as defining the entire visual appearance of the control, and the Content as defining only a subset of the appearance within the template somewhere. When you set the Content of a Button, for example, you're not changing the entire appearance of the button (the button still has a border and background), you only changed what's displayed inside the button at some particular point within the button's visual tree. It is the ContentPresenter 控件的内容(请参阅我的第一个屏幕截图)。

I didn't know I can see the Visual Tree, do I need a special version or such for that?

Visual Studio 具有实时可视化树功能已有一段时间(至少自 2015 年以来),因此除非您拥有 Visual Studio.[=22 的过时版本,否则您应该拥有该功能=]