【问题标题】:UWP: Button without ControlTemplate behaving different than with oneUWP:没有 ControlTemplate 的按钮与一个按钮的行为不同
【发布时间】:2016-10-17 19:34:15
【问题描述】:

可能,我理解的东西根本上是错误的,但根据我的阅读,ControlTemplate-Property 允许我完全定义控件的外观,而无需更改其逻辑(如事件等)。

为了进行一些测试,我创建了一个空的 UWP-Project,并创建了一个带有拉伸功能的 Button:

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

正如预期的那样,按钮延伸到整个窗口。 现在,我用基本完全相同的按钮覆盖模板,但作为模板:

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

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

【问题讨论】:

    标签: uwp uwp-xaml


    【解决方案1】:

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

    <Grid>
        <ContentPresenter/>
    </Grid>
    

    检查 Live Visual Tree 中的按钮可以确认这一点:

    所以您看到 Grid 并没有替换 Button 元素,Button 仍然是可视化树中的 Button,而是模板定义了 Button 的直接子元素。

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

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

    然后你会得到这个可视化树:

    Horizo​​​​ntalAlignment之所以不起作用,是因为它应用于内部按钮而不是外部按钮。作为布局过程的一部分,外部 Button(父级)决定了内部 Button(子级)的大小和位置,由于父级没有被拉伸,它只能容纳显示孩子。

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

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

    将按钮的模板设置为按钮没有意义。看起来你想要做的是设置一个样式,然后你可以为模板和父级的水平对齐设置一个设置器。

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

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


    编辑

    那么,每个控件,即使没有模板,在 VisualTree 中都有一个外观,因此需要定位?

    我不确定您所说的“目标”是什么意思,但是是的,每个控件和控件派生类都有一个可以指定的模板。每个控件都有一个default style,它设置控件的模板(以及其他属性)。如果你对这些风格感兴趣,我推荐你Default control styles and templates

    然后模板只覆盖控件的“内容”?

    没有。 ContentControl(如按钮)的内容与模板不同。将模板视为定义控件的整个视觉外观,将内容视为仅定义模板内某处外观的子集。例如,当您设置按钮的内容时,您并没有更改按钮的整个外观(按钮仍然有边框和背景),您只是更改了按钮视觉范围内某个特定点处按钮内显示的内容树。显示内容的是ContentPresenter 控件(参考我的第一个屏幕截图)。

    我不知道我可以看到可视化树,我需要特殊版本吗?

    Visual Studio 拥有 Live Visual Tree 功能已有一段时间了(至少从 2015 年开始),因此除非您拥有过时的 Visual Studio 版本,否则您应该拥有该功能。

    【讨论】:

    • 谢谢,我只是想用我的“按钮中的按钮”方法测试行为。那么,每个控件,即使没有模板,在 VisualTree 中都有一个外观,因此需要定位?然后模板只覆盖控件的“内容”?我不知道我可以看到 Visual Tree,我需要特殊版本吗?
    • @MatthiasMüller:Live Visual Tree 以及 Live Property Explorer 内置于 Visual Studio 2015(任何版本)中,如下所述Inspect XAML properties while debugging.
    • @MatthiasMüller 我已经编辑了关于您的 cmets 的答案。
    • 如何在后面的C#代码中实现这个逻辑,比如Style、Setter属性模板
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-14
    相关资源
    最近更新 更多