首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用于两个触发器的模板属性设置器

问用于两个触发器的模板属性设置器
EN

Stack Overflow用户
提问于 2019-03-17 09:55:28
回答 1查看 104关注 0票数 0

WPF。考虑以下使用模板的样式,以及它如何影响MenuItem上的填充。(这些是从github的MaterialDesignTheme.Menu.xaml of MaterialDesignThemes.Wpf中的样式中从http://materialdesigninxaml.net/中提取的与填充相关的线条。)

代码语言:javascript
复制
<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>

很容易覆盖默认的填充行。

代码语言:javascript
复制
<Setter Property="Padding" Value="24 0"></Setter>

就像这样:

代码语言:javascript
复制
            <Style TargetType="MenuItem" BasedOn="{StaticResource MaterialDesignMenuItem}">
                <Setter Property="Padding" Value="4 0"></Setter>
            </Style>

我找不到的是如何定义两个TopLevel.触发器,以便可以覆盖它们的公共填充值"16 0"。

在实际代码中,这些触发器做得更多,所以我不想完全覆盖触发器;我必须复制其余的触发器代码。

我想让原始样式为这些指定一个默认值,我可以重写它。类似于:

代码语言:javascript
复制
<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>
...

然后覆盖:

代码语言:javascript
复制
            <Style TargetType="MenuItem" BasedOn="{StaticResource MaterialDesignMenuItem}">
                <Setter Property="Padding" Value="4 0"></Setter>
                <Setter TopPadding="Padding" Value="4 0"></Setter>
            </Style>

但是当然,在TopPadding上没有“MenuItem”属性,所以这不会编译。

如何在原始样式中创建这个新属性,在模板中引用它-在两个触发器中,然后在我的自定义样式中重写它?

可能相关的答案:

Bind to resource keys on each item

Bind to attached property

最坏的情况是,我可以子类MenuItem,并创建一个只适用于该子类的模板(添加"TopPadding“属性)。我不喜欢这样做,因为这是一个复杂库的一部分;我希望有一个模板可以与任何MenuItem一起工作。我认为这意味着任何附加的属性都必须是可选的( MenuItem可能没有它)。我不确定模板将如何引用附加属性,也不确定如果缺少默认属性,如何设置默认属性。

重要的是:我不希望黑客使用Tag属性;我想要一种可扩展的方法,以某种方式添加适当的属性或资源。

更新

我刚刚找到了this answer;我没有意识到附加属性不必在原始类中定义--可以在不对MenuItem进行子类分类的情况下定义一个属性。

我不清楚是否可以设置默认值,以防这个附加属性丢失,但我现在正尝试这样做。

EN

回答 1

Stack Overflow用户

发布于 2019-03-17 11:39:48

不工作尝试,使用this answer的思想

在库中的c#类中定义附加属性:

代码语言:javascript
复制
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
    }
}

试图在模板中使用附加属性:

代码语言:javascript
复制
    <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>

用法(在不同的程序集中):

代码语言:javascript
复制
    <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"/>确实被触发器覆盖;触发器似乎没有找到附加属性,因此重置填充为0。

如果我在触发器的填充中恢复原始的"16 0"值,那么菜单项就会得到这个填充。

我还尝试将TopPadding添加到最后的样式中,但是没有找到在视觉设计器中没有抱怨的语法。(无论如何,我运行了这个程序,但仍然没有效果。)我尝试的语法:

代码语言:javascript
复制
<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>

给出了设计时工具提示:

代码语言:javascript
复制
'' is not a valid value for the 'MaterialDesignThemes.Wpf.ThemeAssist.TopPadding' property on a Setter.

我说的Value="12 0 12 0"很奇怪,但是错误消息显示了一个空白值''。无法将字符串应用于厚度转换器?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55205833

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档