2

目的是在不同的地方重用这个 MultiBinding

<MultiTrigger.Conditions>
    <Condition Value="True">
        <Condition.Binding>
                <MultiBinding Converter="{StaticResource ValidationBooleanConverter}">
                    <Binding X" />
                    <Binding Y" />
                    <Binding Z" />        
                </MultiBinding>
        </Condition.Binding>
    </Condition>
</MultiTrigger.Conditions>

当前不太干燥的条件 (n+)

<Style x:Key="AnErrorTemplate" TargetType="FrameworkElement">
 <Style.Triggers>
    <MultiTrigger>
         <!-- Repeating the whole MultiTrigger.Conditions block here ---> 
         <Setter Property="Validation.ErrorTemplate" Value="{StaticResource DirtyErrorControlTemplate}" />
    </MultiTrigger>
 </Style.Triggers>

<Style x:Key="AnotherStyle" TargetType="FrameworkElement">
 <Style.Triggers>
    <MultiTrigger>
         <!-- Repeating the whole MultiTrigger.Conditions block here ---> 
         <Setter Property="Other" Value="SomeValueIfTheSameConditionsAreTrue" />
    </MultiTrigger>
 </Style.Triggers>

事实上,要求更广泛,因为我还需要在 ControlTemplates 中重复使用这些相同的条件。

<ControlTemplate x:Key="InlineErrorControlTemplate" TargetType="{x:Type Control}">
    <TextBlock Text="{Binding ElementName=InputView, Path=(Validation.Errors)[0].ErrorContent}" Foreground="Red"/>
     <ControlTemplate.Triggers>
         <MultiTrigger>
            <!-- Repeating the whole MultiTrigger.Conditions block here ---> 
            <Setter Property="Visibility" Value="SetMeIfTheseSameTriggerConditionsHold" />
        </MultiTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

易于维护的雨伞?

有什么想法可以只指定一次 MultiTrigger.Conditions 或 MultiBinding,然后在多个样式和控件模板中使用它吗?

  • 仅在 XAML 中?
4

2 回答 2

3

这正是Style inheritanceWPF 中提供的原因。另外,在您的情况下,我建议使用DataTriggerwithMultiBinding而不是MultiTriggerwith MultiBinding...

为了证明这一点,假设我正在创建一个样式来检查TooltiporName分配给 anyFrameworkElement是否为空。如果是这样,如果是a ,它将变为Foreground红色,如果FrameworkElement是,ComboBox它将Background变为黄色。FrameworkElementTextBox

我正在使用...Tag的杂项领域FrameworkElement

因此,对此的所有 XAML(加上 C# 转换器)解决方案如下......

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Height="300" Width="300">
    <Window.Resources>
        <local:AtleastOneEmptyConverter x:Key="AtleastOneEmptyConverter"/>
        <Style x:Key="BaseFrameworkElementStyle"
               TargetType="{x:Type FrameworkElement}">
            <Style.Triggers>
                <DataTrigger Value="True">
                    <DataTrigger.Binding>
                      <MultiBinding
                      Converter="{StaticResource AtleastOneEmptyConverter}">
                            <Binding Path="ToolTip"
                                     RelativeSource="{RelativeSource Self}"/>
                            <Binding Path="Name"
                                     RelativeSource="{RelativeSource Self}"/>
                        </MultiBinding>
                    </DataTrigger.Binding>
                    <Setter Property="Tag" Value="1"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>

        <Style x:Key="ApplyToComboStyle"
               TargetType="{x:Type ComboBox}"
               BasedOn="{StaticResource BaseFrameworkElementStyle}">
            <Style.Triggers>
                <DataTrigger
                    Binding="{Binding Tag,
                            RelativeSource={RelativeSource Self}}" Value="1">
                    <Setter Property="Foreground" Value="Red"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>

        <Style x:Key="ApplyToTextBoxStyle"
               TargetType="{x:Type TextBox}"
               BasedOn="{StaticResource BaseFrameworkElementStyle}">
            <Style.Triggers>
                <DataTrigger
                    Binding="{Binding Tag,
                            RelativeSource={RelativeSource Self}}" Value="1">
                    <Setter Property="Background" Value="Yellow"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel>
        <ComboBox Style="{StaticResource ApplyToComboStyle}"
                  x:Name="NotRedComboBox"
                  ToolTip="You will not see red text here">
            <ComboBoxItem IsSelected="True">I am not Red!</ComboBoxItem>
        </ComboBox>
        <ComboBox Style="{StaticResource ApplyToComboStyle}">
            <ComboBoxItem IsSelected="True">I am Red!</ComboBoxItem>
        </ComboBox>
        <Separator Margin="5"/>
        <TextBox Style="{StaticResource ApplyToTextBoxStyle}"
                 Text="I am yellow"
                 x:Name="YellowTextBox"/>
        <TextBox Style="{StaticResource ApplyToTextBoxStyle}"
                 Text="I am not yellow"
                 x:Name="NotYellowTextBox"
                 ToolTip="You will not see yellow background here"/>
    </StackPanel>
</Window>

C#转换器:

public class AtleastOneEmptyConverter : IMultiValueConverter
{
    public object Convert
        (object[] values, Type targetType,
         object parameter, CultureInfo culture)
    {
        return values.Cast<string>().Any(val => string.IsNullOrEmpty(val));
    }

    public object[] ConvertBack
        (object value, Type[] targetTypes,
        object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
于 2012-05-16T08:03:17.967 回答
2

我已经多次遇到这种情况,我想通过从 Binding 继承并通过指定重用它们来重用设置转换器的常用绑定、这些转换器中的验证规则、源/目标更新通知等:

Foreground="{b:CustomColorBinding CustomDateTime}"

减少我需要为绑定键入的 XAML 数量,但不要相信有办法将它全部保存在 XAML 中。不幸的是,尝试设置 x:Key 并像使用静态或动态资源一样使用它是不可能的。我已经非常习惯于使用这种约定,因此我为我的项目创建了一个 BindingCatalog 来存储我为绑定到不同类型的不同控件的常见(多)绑定场景。

我相信你有充分的理由想要避免代码隐藏,但如果你可以在代码中创建你的 MultiBinding 一次并重用它来干燥你的 XAML——那么我认为它不仅仅是证明(过度妖魔化,恕我直言)执行此操作所需的代码。

希望这有助于决定做什么!

扩展绑定

namespace MyNamespace
{
    public class CustomBinding : Binding
    {
        public CustomBinding(String path)
            : base(path)
        {
            this.Converter = new CustomValueConverter();
            this.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            this.ValidatesOnDataErrors = true;
        }
    }
}

其 XAML 用法

<UserControl x:Class="MyNamespace.UserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:MyNamespace">
    <StackPanel>
        <TextBox Text="{local:CustomBinding MyViewModelProperty}"/>
    </StackPanel>
</UserControl>
于 2012-05-16T03:52:12.483 回答