Свяжите свойства со стилями, определенными в ResourceDictionary, чтобы исключить дублирование кода

У меня есть следующий код XAML:

<Window x:Class = "LinkButton.MainWindow"
        xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local = "clr-namespace:LinkButton"
        mc:Ignorable = "d"
        Title = "MainWindow" Height = "350" Width = "525"
        DataContext = "{StaticResource MainWindowVM}">

    <Window.Resources>
        <Style TargetType = "TextBlock">
            <Setter Property = "Margin" Value = "10" />
        </Style>
    </Window.Resources>

    <Grid>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width = "Auto" />
            <ColumnDefinition Width = "Auto" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height = "Auto" />
            <RowDefinition Height = "Auto" />
        </Grid.RowDefinitions>

        <TextBlock Grid.Row = "0" Grid.Column = "0" Text = "ddk" />
        <TextBlock Grid.Row = "0" Grid.Column = "1" >
             <Hyperlink Command = "{Binding Link}"  
                       CommandParameter = "{Binding}"
                       Foreground = "Blue" >
               <Hyperlink.Inlines>
                   <TextBlock>
                        <TextBlock.Style>
                            <Style>
                                <Setter Property = "TextBlock.Text" Value = "{Binding Description01.Header}" />
                            </Style>
                        </TextBlock.Style>
                   </TextBlock>
               </Hyperlink.Inlines>
                </Hyperlink>
        </TextBlock>
        <TextBlock Grid.Row = "1" Grid.Column = "0" Text = "dde" />
        <TextBlock Grid.Row = "1" Grid.Column = "1">
            <Hyperlink Command = "{Binding Link}"  
                       CommandParameter = "{Binding}"
                       Foreground = "Blue" >
               <Hyperlink.Inlines>
                   <TextBlock>
                        <TextBlock.Style>
                            <Style>
                                <Setter Property = "TextBlock.Text" Value = "{Binding Description11.Header}" />
                            </Style>
                        </TextBlock.Style>
                   </TextBlock>
               </Hyperlink.Inlines>
                </Hyperlink>
        </TextBlock>
    </Grid>
</Window>

И код кода C#:

public class TestCommand : ICommand
{
    public delegate void ICommandOnExecute(object parameter);
    public delegate bool ICommandOnCanExecute(object parameter);

    private ICommandOnExecute _execute;
    private ICommandOnCanExecute _canExecute;

    public TestCommand(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod)
    {
        _execute = onExecuteMethod;
        _canExecute = onCanExecuteMethod;
    }

    #region ICommand Members

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute.Invoke(parameter);
    }

    public void Execute(object parameter)
    {
        _execute.Invoke(parameter);
    }

    #endregion
}

public class LongDescription
{
    public string Header { get; }
    public string Description { get; }
    public LongDescription(string header, string description)
    {
        Header = header;
        Description = description;
    }
}

public class MainWindowVM
{



    public ICommand Link => new TestCommand(ExecuteCommand1, CanExecuteCommand1);

    public LongDescription Description11 => new LongDescription("cell11", "result cell11");
    public LongDescription Description01 => new LongDescription("cell01", "result cell01");

    public bool CanExecuteCommand1(object parameter)
    {
        return true;
    }

    public void ExecuteCommand1(object parameter)
    {
        MessageBox.Show("Executing command 1");
    }

}

Понятно, что я продублировал код в XAML (<Hyperlink.Inlines> и т. д.). Я хочу его реорганизовать, чтобы исключить дублирование кода. Для этого я подумываю определить стиль <Hyperlink.Inlines> в ResourceDictionary, а затем связать его с соответствующими свойствами в MainWindowVM.

Но я не уверен, как это сделать, есть идеи?

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

Ответы 1

Ответ принят как подходящий

Вы можете легко переместить стиль в ResourceDictionary следующим образом

<ResourceDictionary xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml">

    <!-- Key is required to identify the Style -->
    <Style x:Key = "Bind01" TargetType = "TextBlock">
        <Setter Property = "Text" Value = "{Binding Description01.Header}" />
    </Style>

    <Style x:Key = "Bind11" TargetType = "TextBlock">
        <Setter Property = "Text" Value = "{Binding Description11.Header}" />        
    </Style>
</ResourceDictionary>

И объедините словарь в своем окне, чтобы использовать стиль

Объединить

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source = "YourDictionaryHere"/>
        </ResourceDictionary.MergedDictionaries>

    <Style TargetType = "TextBlock">
        <Setter Property = "Margin" Value = "10" />
    </Style>
    </ResourceDictionary>
</Window.Resources>

Использовать

<TextBox Style = "{DynamicResource Bind01}"/>

Упрощение

Вместо того, чтобы помещать переменную Binding в Style (или Dictionary), я предлагаю записать переменную Bindings непосредственно в Control, а остальное определить как Style.

Более конкретный: следующая разметка отображает связанную строку как Hyperlink, которая при нажатии выполняет команду ICommand.

    <TextBlock>
        <Hyperlink Command = "{Binding Link}"  
                   CommandParameter = "{Binding}"
                   Foreground = "Blue" >
           <Hyperlink.Inlines>
               <TextBlock>
                    <TextBlock.Style>
                        <Style>
                            <Setter Property = "TextBlock.Text" Value = "{Binding Description11.Header}" />
                        </Style>
                    </TextBlock.Style>
               </TextBlock>
           </Hyperlink.Inlines>
            </Hyperlink>
    </TextBlock>

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

Стиль кнопки

    <Style x:Key = "LinkStyle" TargetType = "Button">
        <Setter Property = "Template">
            <Setter.Value>
                <ControlTemplate TargetType = "Button">
                    <TextBlock>
                        <Hyperlink Command = "{Binding Link}" CommandParameter = "{Binding}">
                            <Run Text = "{TemplateBinding Content}"/>
                        </Hyperlink>
                    </TextBlock>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Применить стиль к элементам в сетке (заменить TextBlock на кнопки со стилем)

    <TextBlock Grid.Row = "0" Grid.Column = "0" Text = "ddk" />
    <Button Grid.Row = "1" Grid.Column = "1" 
            Content = "{Binding Description01.Header}" 
            Style = "{DynamicResource LinkStyle}">
    <TextBlock Grid.Row = "1" Grid.Column = "0" Text = "dde" />
    <Button Grid.Row = "1" Grid.Column = "1" 
            Content = "{Binding Description11.Header}" 
            Style = "{DynamicResource LinkStyle}">

Экраны (пунктирные линии - линии сетки)

Runtime

Редактировать

Чтобы установить Command в Hyperlink, мы используем свойство Command кнопки для установки привязки. Поэтому мы должны добавить TemplateBinding в наш стиль. Замените «жестко запрограммированный» Command с TemplateBinding на ButtonCommand. Сделайте то же самое для параметра Command.

             <Hyperlink Command = "{TemplateBinding Command}"  
                   CommandParameter = "{Templatebinding Commandparameter}"
                   Foreground = "Blue" >

И установите Command и CommandParameter в стилизованном Button

    <TextBlock Grid.Row = "0" Grid.Column = "0" Text = "ddk" />
<Button Grid.Row = "1" Grid.Column = "1" 
        Content = "{Binding Description01.Header}"
        Command = "{Binding YOURCOMMANDHERE}"
        CommandParameter = "{YOURPARAMETER}" 
        Style = "{DynamicResource LinkStyle}">
<TextBlock Grid.Row = "1" Grid.Column = "0" Text = "dde" />
<Button Grid.Row = "1" Grid.Column = "1" 
        Content = "{Binding Description11.Header}"
        Command = "{Binding YOUROTHERCOMMANDHERE}"
        CommandParameter = "{YOUROTHERPARAMETER}"
        Style = "{DynamicResource LinkStyle}">

Как это должно ответить на мой вопрос?

Graviton 02.05.2018 11:40

Насколько я понял, ваша цель - уменьшить количество дублированного кода, верно? Может быть, я немного излишне увлечен и забыл упомянуть, что это решение может упростить два TextBlocks и Hyperlink вместо небольшой части стиля Hyperlink.Inlines. Если это соответствует вашим потребностям, я обновлю свой ответ.

LittleBit 02.05.2018 11:52

«Можно упростить» - можете ли вы уточнить и дать исчерпывающий ответ?

Graviton 02.05.2018 12:10

Обновлено, надеюсь, это объяснение более ясное и ответ на исходный вопрос.

LittleBit 02.05.2018 12:38

Ваш код "Стиль кнопки" не работает - кнопка, дублированная как ссылка, просто не появляется вообще при запуске. Вы тестировали собственное решение?

Graviton 03.05.2018 06:48

Конечно, см. Экраны в ответе. Если ничего не отображается, возможно, проблема в привязке. Что-то отображается в консоли? Другой вопрос: планируете ли вы расширить эту сетку более чем на 2 записи? Если да, то во время выполнения? (Я спрашиваю, потому что другой подход с DataGrid может лучше соответствовать вашим потребностям, чем этот)

LittleBit 03.05.2018 10:16

Другой вопрос, скажем, если я хочу передать команду (вместо жесткого кода <Hyperlink Command = "{ Binding Link}" CommandParameter = "{Binding}">), возможно ли это?

Graviton 03.05.2018 10:40

Да, это возможно, см. Edit. Мы привязываем команду и параметр Hyperlink к команде и параметру Button. При этом он может (и должен) быть установлен вне стиля (если вы не установите его, команда для выполнения отсутствует и выдает ошибку).

LittleBit 03.05.2018 10:58

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