Привязка к вложенному свойству внутри ControlTemplate

Цель состоит в том, чтобы создать словарь ресурсов с геометрией путей к значкам для моего настраиваемого шаблона кнопки.

Что пока работает:

ResourceDictionary:

<Geometry x:Key = "ArrowDown">
    M0,10 M10,0 M5,1 L5,7 4.2,7 5,8 5.8,7 5,7
</Geometry>
<Geometry x:Key = "ArrowUp">
    M0,0 M10,10 M5,9 L5,3 4.2,3 5,2 5.8,3 5,3
</Geometry>

Прикрепленное свойство для Пути:

public static Geometry GetIconPath(UIElement element)
{
    return (Geometry)element.GetValue(IconPathProperty);
}

public static void SetIconPath(UIElement element, Geometry value)
{
    element.SetValue(PIconPathProperty, value);
}

public static readonly DependencyProperty IconPathProperty =
    DependencyProperty.RegisterAttached("IconPath", typeof(Geometry), typeof(Attached));

Шаблон:

<ControlTemplate x:Key = "ButtonTemplate" TargetType = "{x:Type Button}">
    <Viewbox>
        <Path Name = "Icon" Stroke = "Black" StrokeThickness = "1" Stretch = "Uniform"
              Data = "{Binding (local:Attached.IconPath), RelativeSource = {RelativeSource TemplatedParent}}"/>
    </Viewbox>
    <ControlTemplate.Triggers>
        <Trigger Property = "IsEnabled" Value = "False">
            <Setter Property = "Stroke" TargetName = "Icon" Value = "Gray"/>
            <Setter TargetName = "Icon" Property = "Effect">
                <Setter.Value>
                    <DropShadowEffect ShadowDepth = "0.2" Color = "Black" Direction = "125"/>
                </Setter.Value>
            </Setter>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

Кнопка:

<Button local:Attached.IconPath = "{StaticResource ArrowDown}"/>

Это работает нормально, но теперь у меня есть дополнительный уровень сложности: некоторые значки нужно заливать, а другие - нет. И я хотел бы, чтобы эта информация была в ResourceDictionary с помощью GeometryData.

Одним из решений было бы сохранить весь Path в ResourceDictionary, но, как вы можете видеть в ControlTemplate, мне нужно иметь доступ к Path для запуска DropShadowEffect.

Итак, альтернативное решение, которое я пытаюсь использовать, - использовать POCO для хранения обоих элементов в:

public class IconData
{
    public bool Fill { get; set; }
    public Geometry Geometry { get; set; }
}

Итак, ResourceDictionary теперь содержит:

<local:IconData x:Key = "ArrowUp" Fill = "True" Geometry = "
    M0,0 M10,10 M5,9 L5,3 4.2,3 5,2 5.8,3 5,3"/>

С соответствующим присоединенным свойством ControlTemplate становится:

<ControlTemplate x:Key = "ButtonTemplate" TargetType = "{x:Type Button}">
    <Viewbox>
        <Path Name = "Icon" Stroke = "Black" StrokeThickness = "1" Stretch = "Uniform"
              Data = "{Binding (local:Attached.IconData.Geometry), RelativeSource = {RelativeSource TemplatedParent}}"/>
    </Viewbox>
    <ControlTemplate.Triggers>
        <Trigger Property = "local:Attached.IconData.Fill" Value = "True">
            <Setter Property = "Fill" TargetName = "Icon" Value = "#00000000"/>
        </Trigger>
        <Trigger Property = "IsEnabled" Value = "False">
            <Setter Property = "Stroke" TargetName = "Icon" Value = "Gray"/>
            <Setter TargetName = "Icon" Property = "Effect">
                <Setter.Value>
                    <DropShadowEffect ShadowDepth = "0.2" Color = "Black" Direction = "125"/>
                </Setter.Value>
            </Setter>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

И, к сожалению, обе ссылки на IconData здесь говорят о Nested types are not supported: Attached.IconData.

Я открыт для решения моей реализации, любого обходного пути или другого решения.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
0
600
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
<Path Name = "Icon" Stroke = "Black" StrokeThickness = "1" Stretch = "Uniform"
      Data = "{Binding (local:Attached.IconData.Geometry), RelativeSource = {RelativeSource TemplatedParent}}"/>

Здесь (local:Attached.IconData.Geometry) означает вложенный тип. Чтобы получить свойство объекта Attached.IconData, необходимо использовать следующий путь привязки:

<Path Name = "Icon" Stroke = "Black" StrokeThickness = "1" Stretch = "Uniform"
      Data = "{Binding (local:Attached.IconData).Geometry, RelativeSource = {RelativeSource TemplatedParent}}"/>

Также не забудьте изменить присоединенный тип свойства с Geometry на IconData в типе Attached.

Класс IconData не должен быть вложен в какой-либо тип, потому что это именно то, что считается не поддерживаемым (просто поместите в то же пространство имен, что и другие используемые типы).

После этих модификаций ваш код начал у меня работать.

Вот главное окно XAML:

<Window x:Class = "WpfApplication1.MainWindow"
        xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local = "clr-namespace:WpfApplication1"
        Title = "MainWindow" Height = "250" Width = "260">
    <Window.Resources>
        <ResourceDictionary>
            <local:IconData x:Key = "ArrowUp" Fill = "False" Geometry = "M0,0 M10,10 M4.8,9 4.8,3 4.2,3 5,2 5.8,3 5.2,3 5.2,9 Z"/>
            <ControlTemplate x:Key = "ButtonTemplate" TargetType = "{x:Type Button}">
                <Viewbox>
                    <Path Name = "Icon" Stretch = "Uniform"
                          Data = "{Binding (local:Attached.IconPath).Geometry, RelativeSource = {RelativeSource TemplatedParent}}">
                        <Path.Style>
                            <Style TargetType = "Path">
                                <Style.Triggers>
                                    <DataTrigger Binding = "{Binding (local:Attached.IconPath).Fill, RelativeSource = {RelativeSource TemplatedParent}}"
                                                     Value = "True">
                                        <Setter Property = "Fill" Value = "Black" />
                                    </DataTrigger>
                                    <DataTrigger Binding = "{Binding (local:Attached.IconPath).Fill, RelativeSource = {RelativeSource TemplatedParent}}"
                                                     Value = "False">
                                        <Setter Property = "Stroke" Value = "Black" />
                                        <Setter Property = "StrokeThickness" Value = "0.2" />
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </Path.Style>
                    </Path>
                </Viewbox>
            </ControlTemplate>

        </ResourceDictionary>
    </Window.Resources>

    <Button local:Attached.IconPath = "{StaticResource ArrowUp}" Template = "{StaticResource ButtonTemplate}" />
</Window>

Обратите внимание, что я изменил геометрию пути на M0,0 M10,10 M4.8,9 4.8,3 4.2,3 5,2 5.8,3 5.2,3 5.2,9 Z, чтобы сделать его замкнутым и, таким образом, подходящим для заливки.

Вот скриншоты кейсов <local:IconData Fill = "False" ... /> и <local:IconData Fill = "True" ... />:

A screenshot for case Fill=FalseA screenshot for case Fill=True

Он строится, но я почему-то не вижу пути. Вы зашли так далеко?

Benjol 19.03.2018 08:53

Другие вопросы по теме