如何将自定义的 Controltemplate 设置为整个应用程序的默认值?

4
我决定尝试自定义菜单和菜单项的默认控件模板的多个方面。在Visual Studio中,我选择了我的菜单,在属性面板中找到“Template”,并选择“转换为新资源...”。
我对MenuItem做了同样的事情。然后,只是为了测试,我将MenuItem SubMenuBorder颜色改为红色。此时,我有了一个包含两个ControlTemplates的资源字典,以及一个看起来像这样的菜单:
<Menu Template="{DynamicResource CustomMenuControlTemplate}">
    <MenuItem Header="File" Template="{DynamicResource CustomMenuItemControlTemplate}">
        <MenuItem Header="Test 1" />
        <MenuItem Header="Test 2">
            <MenuItem Header="Subtest 1" />
            <MenuItem Header="Subtest 2" />
            <MenuItem Header="Subtest 3" />
        </MenuItem>
        <MenuItem Header="Test 3" />
    </MenuItem>
</Menu>

Menu 1

问题在于,只有在我明确将模板设置为修改后的CustomMenuItemControlTemplate时,红色边框才会出现在菜单项上。如果我想在所有菜单项上使用我的模板,我必须包含以下内容:
Template="{DynamicResource CustomMenuItemControlTemplate}"

我希望在我的整个应用程序中为每个菜单项设置命令。

因此,接下来我想创建一个适用于所有菜单项的样式,并使用setter设置默认模板:

<Style TargetType="MenuItem">
    <Setter Property="Template" Value="{DynamicResource CustomMenuItemControlTemplate}" />
</Style>

这个可以工作(请注意所有子菜单上的红色边框),但出于某种原因,它会极大地改变菜单的外观:

Menu 2

在那个setter中,我尝试使用DynamicResource和StaticResource绑定,结果相同。
所以,我的主要问题是:有没有办法将自定义ControlTemplate用作默认值,这样我就不必在每个控件上显式设置它了?次要问题:为什么使用样式来设置模板属性会导致外观发生如此巨大的变化?
2个回答

3

在WPF中,如果没有Key值,就不能放置控件模板,而且Key值也不能使用{x:Type ...}

但是你可以放置一个没有Key值的Style,这个样式将成为默认样式。并且在这个样式中,你可以设置控件模板。

<Style TargetType="{x:Type MenuItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type MenuItem}">
                <!-- Insert Control Template Here -->
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>


这是正确的答案。 - sjoshua270

2

回答你的第一个问题:

如果你将控件模板放在app.xaml的资源字典中,它将应用于整个应用程序。你的控件模板头应该像这样:

<ControlTemplate TargetType="MenuItem" ...(other properties)>

这将使所有MenuItem控件隐式使用该控件模板。

回答你的第二个问题:

这是因为添加样式会覆盖默认样式,实质上删除了所有内置样式。如果你只想改变一些东西,style标签应该像这样:

<Style BasedOn="{StaticResource {x:Type MenuItem}}" ...(other properties)>

这样它会继承所有常规的样式,并且只更改您明确定义的样式。

1
现在我明白了,特别是关于它如何覆盖默认样式的部分。话虽如此,我尝试将控件模板添加到我的app.xaml中而没有使用键,但我得到了与在资源字典中尝试时相同的错误:“每个字典条目必须有一个关联的键。”您能否请确切地解释应该放在哪里?我将其放在了app.xaml ResourceDictionary标签内部。 - Chronicide
你仍然可以拥有一个键,我在答案中放置的代码只是处理你的问题的重要属性。请随意更改标记中的任何其他属性。如果你想知道为什么你有一个标记和一个TargetType,那么TargetType处理隐式模板化,而Key可用于其他控件类型的显式模板化。这有意义吗? - Gordon Allocman
我修改了我的代码,让它更清晰易懂,方便你或其他人在使用时遇到问题时能够更好地理解。 - Gordon Allocman
3
感谢您的编辑。不幸的是,似乎如果不提供键,您无法将ControlTemplate作为资源使用。因此,即使您设置了TargetType,它也不会被隐式地使用。有了键之后,您必须使用该键绑定模板属性。另外,您提供的关于BasedOn的解释很有道理。然而,使用BasedOn似乎会对布局产生更奇怪的影响。在修改我的问题之前,我将进行更多的BasedOn阅读。感谢您迄今为止的帮助。 - Chronicide
我相信你也可以设置x:Key = "{x:Type MenuItem}",这样应该可以隐式地保持模板工作。如果有效,我会编辑我的答案。如果不起作用,您可以将控件模板复制一次到每个视图的xaml文件中,这样您就不需要指定x:Key了。 - Gordon Allocman
3
无法将类型用作键。这个答案根本没有回答问题。 - BrainSlugs83

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