WPF。考虑以下带有模板的样式,以及它如何影响MenuItem
上的填充。 (这些是与填充相关的行,是从http://materialdesigninxaml.net/的github中MaterialDesignTheme.Menu.xaml
的{{1}}中的样式中提取的。)
MaterialDesignThemes.Wpf
很容易覆盖默认的填充线
<Style TargetType="{x:Type MenuItem}" x:Key="MaterialDesignMenuItem" BasedOn="{x:Null}">
<Setter Property="Padding" Value="24 0"></Setter>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<ControlTemplate.Resources>
</ControlTemplate.Resources>
<Grid ClipToBounds="True">
</Grid>
<ControlTemplate.Triggers>
<!--#region Roles Triggers -->
<Trigger Property="Role" Value="TopLevelHeader">
<Setter Property="Padding" Value="16 0"/>
</Trigger>
<Trigger Property="Role" Value="TopLevelItem">
<Setter Property="Padding" Value="16 0"/>
</Trigger>
<!--#endregion-->
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
像这样:
<Setter Property="Padding" Value="24 0"></Setter>
我一直无法找到的是如何定义两个TopLevel ...触发器,以便可以覆盖它们的公共填充值 <Style TargetType="MenuItem" BasedOn="{StaticResource MaterialDesignMenuItem}">
<Setter Property="Padding" Value="4 0"></Setter>
</Style>
。
在实际的代码中,这些触发器的作用更大,所以我不想完全覆盖触发器。我必须重复其余的触发代码。
我想让原始样式为这些样式指定一个默认值,我可以覆盖它。像这样:
"16 0"
然后覆盖:
<Style TargetType="{x:Type MenuItem}" x:Key="MaterialDesignMenuItem" BasedOn="{x:Null}">
<Setter Property="Padding" Value="24 0"></Setter>
<Setter Property="TopPadding" Value="16 0"></Setter>
...
但是,当然,MenuItem上没有“ TopPadding”属性,因此无法编译。
如何在原始样式中创建此新属性,在模板中(在两个触发器中)引用它,然后以自定义样式覆盖它?
可能相关的答案:
Bind to resource keys on each item
Bind to attached property
最坏的情况是,我可以将MenuItem子类化,并制作一个仅适用于该子类的模板(添加“ TopPadding”属性)。我不想这样做,因为它是复杂库的一部分。我想要一个可以与任何MenuItem一起使用的模板。我认为这意味着任何附加属性都必须是可选的(MenuItem可能没有此属性。)我不确定模板如何引用附加属性,也不确定如何设置默认属性。
重要提示:我不希望使用 <Style TargetType="MenuItem" BasedOn="{StaticResource MaterialDesignMenuItem}">
<Setter Property="Padding" Value="4 0"></Setter>
<Setter TopPadding="Padding" Value="4 0"></Setter>
</Style>
属性的骇客;我想要一种可扩展的方法,以某种方式添加适当的属性或资源。
更新
我刚发现this answer;我没有意识到不必在原始类中定义附加属性-可以在不继承MenuItem的情况下定义附加属性。
我不清楚是否可以设置 default 值,以防丢失此附加属性,但是我现在正在尝试这样做。
答案 0 :(得分:0)
不工作,尝试使用this answer中的想法:
在该库的c#类中定义附加属性:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace MaterialDesignThemes.Wpf
{
public static class ThemeAssist
{
// ...
#region TopPadding AttachedProperty
public static DependencyProperty TopPaddingProperty =
DependencyProperty.RegisterAttached("TopPadding",
typeof(Thickness),
typeof(ThemeAssist),
new PropertyMetadata(new Thickness(12, 0, 12, 0)));
public static void SetTopPadding(DependencyObject obj, Thickness value)
{
obj.SetValue(TopPaddingProperty, value);
}
public static Brush GetTopPadding(DependencyObject obj)
{
return (Brush)obj.GetValue(TopPaddingProperty);
}
#endregion
}
}
尝试在模板中使用该附加属性:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpf="clr-namespace:MaterialDesignThemes.Wpf"
xmlns:converters="clr-namespace:MaterialDesignThemes.Wpf.Converters">
<!-- ... -->
<Style TargetType="{x:Type MenuItem}" x:Key="MaterialDesignMenuItem" BasedOn="{x:Null}">
<Setter Property="Padding" Value="24 0"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="wpf:ThemeAssist.TopPadding" Value="16 0 16 0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<ControlTemplate.Resources>
</ControlTemplate.Resources>
<Grid ClipToBounds="True">
</Grid>
<ControlTemplate.Triggers>
<!--#region Roles Triggers -->
<Trigger Property="Role" Value="TopLevelHeader">
<!-- <Setter Property="Padding" Value="16 0"/> -->
<Setter Property="Padding" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(wpf:ThemeAssist.TopPadding)}"/>
</Trigger>
<Trigger Property="Role" Value="TopLevelItem">
<!--<Setter Property="Padding" Value="16 0"/>-->
<Setter Property="Padding" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(wpf:ThemeAssist.TopPadding)}"/>
</Trigger>
<!--#endregion-->
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
用法(在不同的程序集中):
<StackPanel DockPanel.Dock="Top">
<StackPanel.Resources>
<Style TargetType="MenuItem" BasedOn="{StaticResource MaterialDesignMenuItem}">
<Setter Property="Padding" Value="24 0 24 0"/>
<!--<Setter Property="wpf:ThemeAssist.TopPadding" Value="12 0 12 0"/>-->
<Setter Property="Background" Value="Aqua"></Setter>
</Style>
</StackPanel.Resources>
<Menu x:Name="MainMenu" IsMainMenu="True" Visibility="Collapsed">
<MenuItem Header="_File">
错误结果:TopLevelHeader / TopLevelItem MenuItem填充始终为(0,0,0,0)。附加属性定义(12, ..)
的默认值或样式设置器<Setter Property="wpf:ThemeAssist.TopPadding" Value="16 0 16 0"/>
的值都无效。
重要的是,最终样式的<Setter Property="Padding" Value="24 0 24 0"/>
确实被触发器覆盖;似乎触发器未找到附加属性,因此已将Padding重置为0。
如果我在触发器的填充中恢复了原始的"16 0"
值,则菜单项会获得该填充。
我还尝试将TopPadding添加到最终样式中,但是没有成功找到在视觉设计器中不会抱怨的语法。 (我仍然运行了该程序,但仍然没有效果。)我尝试的语法:
<UserControl x:Class="GISWPF.Dialogs"
xmlns:wpf="clr-namespace:MaterialDesignThemes.Wpf;assembly=MaterialDesignThemes.Wpf"
...
>
...
<Style TargetType="MenuItem" BasedOn="{StaticResource MaterialDesignMenuItem}">
<Setter Property="wpf:ThemeAssist.TopPadding" Value="12 0 12 0"/>
</Style>
提供设计时工具提示:
'' is not a valid value for the 'MaterialDesignThemes.Wpf.ThemeAssist.TopPadding' property on a Setter.
奇怪的是我说Value="12 0 12 0"
,但是错误消息显示了空白值''
。无法将字符串应用于厚度转换器?