установщик свойства шаблона для использования в двух триггерах - PullRequest
0 голосов
/ 17 марта 2019

WPF. Рассмотрим следующий стиль с шаблоном и то, как он влияет на заполнение на MenuItem. (Это строки, связанные с отступом, извлеченные из стиля в MaterialDesignTheme.Menu.xaml из MaterialDesignThemes.Wpf в github из http://materialdesigninxaml.net/.)

<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>

вроде так:

            <Style TargetType="MenuItem" BasedOn="{StaticResource MaterialDesignMenuItem}">
                <Setter Property="Padding" Value="4 0"></Setter>
            </Style>

Я не смог найти, как определить два TopLevel ... Триггеры, чтобы их общее значение заполнения "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>
...

Затем переопределить:

            <Style TargetType="MenuItem" BasedOn="{StaticResource MaterialDesignMenuItem}">
                <Setter Property="Padding" Value="4 0"></Setter>
                <Setter TopPadding="Padding" Value="4 0"></Setter>
            </Style>

Но, конечно, в MenuItem нет свойства "TopPadding", поэтому оно не будет компилироваться.

Как мне создать это новое свойство в исходном стиле, обратиться к нему в шаблоне - в двух триггерах, а затем переопределить его в моем настроенном стиле?

Возможные похожие ответы:
Привязка к ресурсным ключам на каждом предмете
Привязать к прикрепленному имуществу

В худшем случае я мог бы создать подкласс MenuItem и создать шаблон, который применяется только к этому подклассу (чтобы добавить свойство "TopPadding"). Я бы предпочел не делать этого, так как это часть сложной библиотеки; Я хотел бы иметь шаблон, который будет работать с любым MenuItem. Я думаю, это означает, что любое вложенное свойство должно быть необязательным (у MenuItem его может не быть.) Я не уверен, как шаблон будет ссылаться на вложенное свойство или как установить значение по умолчанию, если оно отсутствует.

ВАЖНО: я не хочу хак, который использует свойство Tag; Я хочу масштабируемый подход, который каким-то образом добавляет соответствующее свойство или ресурс.


ОБНОВЛЕНИЕ

Я только что нашел этот ответ ; Я не осознавал, что присоединенные свойства не должны быть определены в исходном классе - можно определить одно без подкласса MenuItem.
Мне не ясно, могу ли я установить значение default в случае, если это присоединенное свойство отсутствует, но я пытаюсь сделать это сейчас.

1 Ответ

0 голосов
/ 17 марта 2019

НЕ РАБОТАЮЩАЯ попытка, используя идею из этого ответа :

Определение присоединенного свойства в классе ac # в этой библиотеке:

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 / TopLevelItemMenuItem Заполнение всегда (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",все же сообщение об ошибке показывает пустое значение ''.Не удается применить преобразователь строки в толщину?

...