首页 > 解决方案 > 将属性绑定到 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.

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

标签: xamlresourcedictionary

解决方案


您可以像这样轻松地在 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 放入样式(或字典)中,而是将变量 Binding 直接写入控件并将其余部分定义为样式。

更具体:以下标记将绑定字符串显示为Hyperlink单击时执行 ICommand 的 a。

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

屏幕(虚线是网格线)

运行

编辑

我们使用Button的CommandProperty来设置Binding 。因此我们必须在我们的样式中添加一个。将“硬编码”替换为. 对命令参数执行相同的操作。HyperlinkCommandTemplateBindingCommandTemplateBindingButton Command

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

并在样式中设置CommandCommandParameterButton

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

推荐阅读