将属性绑定到 ResourceDictionary 中定义的样式以消除代码重复

Bind properties to styles defined at ResourceDictionary to eliminate code duplication

我有以下 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> 等)中有重复的代码。我想重构它以消除代码重复。为此,我正在考虑在 ResourceDictionary 中定义样式 <Hyperlink.Inlines>,然后将其绑定到 MainWindowVM 中的适当属性。

但我不确定该怎么做,有什么想法吗?

您可以像这样轻松移动 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 中合并词典以使用样式

合并

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

我们可以为看起来(和做的)相同的按钮定义样式,但可以通过 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}">

屏幕(虚线是网格线)

编辑

要设置HyperlinkCommand我们使用Button的Command属性来设置Binding。因此我们必须在 Style 中添加一个 TemplateBinding。将 "Hard Coded" Command 替换为 TemplateBindingButton Command。对命令参数执行相同操作。

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

并在样式 Button

中设置 CommandCommandParameter
    <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}">