具有特定属性的通用样式

General style with specific properties

我想要一个动态的 ToolTip 样式,它根据不同字符串属性的文本更改前景色(在这个代码示例中,字符串是 PosError,但也可以是任何 属性 名称,如果值为“Error”,则触发 DataTrigger

至于现在,我必须对每个 TextBox 都这样做:更改 DataTrigger 的 属性 绑定和 [=11= 的文本](在这个例子中,字符串 属性 是 PosExtreme):

<TextBox 
    Width="150" 
    FontSize="25"
    MaxWidth="150"
    Name="posTab"
    TextAlignment="Center"
    Text="{Binding PosTabStrength, UpdateSourceTrigger=PropertyChanged}">
    <TextBox.ToolTip>
        <ToolTip>
            <ToolTip.Style>
                <Style TargetType="{x:Type ToolTip}">
                    <Style.Triggers>
                         <DataTrigger Binding="{Binding PosError}" Value="Error">
                             <DataTrigger.Setters>
                                 <Setter Property="Foreground">
                                     <Setter.Value>
                                         <LinearGradientBrush StartPoint="0 0" EndPoint="0 1">
                                             <GradientStop Color="#F08080" Offset="0"/>
                                             <GradientStop Color="#F04080" Offset="1"/>
                                         </LinearGradientBrush>
                                      </Setter.Value>
                                  </Setter>
                              </DataTrigger.Setters>
                          </DataTrigger>
                      </Style.Triggers>
                          <Setter Property="FontSize" Value="16"/>
                          <Setter Property="HasDropShadow" Value="True" />
                          <Setter Property="OverridesDefaultStyle" Value="true" />
                          <Setter Property="Foreground">
                              <Setter.Value>
                                  <LinearGradientBrush StartPoint="0 0" EndPoint="0 1">
                                      <GradientStop Color="#10F080" Offset="0"/>
                                      <GradientStop Color="#10B080" Offset="1"/>
                                  </LinearGradientBrush>
                              </Setter.Value>
                          </Setter>
                          <Setter Property="Template">
                              <Setter.Value>
                                  <ControlTemplate TargetType="ToolTip">
                                      <Border 
                                          CornerRadius="3"
                                          BorderThickness="1"
                                          Background="#CF001233"
                                          SnapsToDevicePixels="True"
                                          Width="{TemplateBinding Width}"
                                          Height="{TemplateBinding Height}">
                                          <Border.Style>
                                              <Style TargetType="{x:Type Border}">
                                                  <Setter Property="BorderBrush">
                                                      <Setter.Value>
                                                          <LinearGradientBrush StartPoint="0 0" EndPoint="0 1">
                                                              <GradientStop Color="#A0A0F0" Offset="0"/>
                                                              <GradientStop Color="#8080F0" Offset="1"/>
                                                              <LinearGradientBrush.RelativeTransform>
                                                                  <RotateTransform CenterX="0.5" CenterY="0.5"/>
                                                              </LinearGradientBrush.RelativeTransform>
                                                          </LinearGradientBrush>
                                                      </Setter.Value>
                                                  </Setter>
                                              <Style.Triggers>
                                                  <EventTrigger RoutedEvent="Border.Loaded">
                                                      <BeginStoryboard>
                                                          <Storyboard RepeatBehavior="Forever">
                                                              <DoubleAnimation 
                                                                  From="359"
                                                                  To="0"
                                                                  Duration="00:00:2" 
                                                                  Storyboard.TargetProperty="(Border.BorderBrush).(Brush.RelativeTransform).(RotateTransform.Angle)"/>
                                                          </Storyboard>
                                                      </BeginStoryboard>
                                                  </EventTrigger>
                                              </Style.Triggers>
                                          </Style>
                                      </Border.Style>
                                  <ContentPresenter Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                              </Border>
                          </ControlTemplate>
                      </Setter.Value>
                  </Setter>
              </Style>
            </ToolTip.Style>
            <TextBlock Text="{Binding PosExtreme}"/>
        </ToolTip>
    </TextBox.ToolTip>
</TextBox>

我想将 ToolTip 样式作为 ResourceDictionary 文件,而不必复制和粘贴代码并为每个 TextBox 修改代码,使其正确 ToolTip 样式和 ToolTip 文本。 这可能吗?

重用样式的主要障碍是绑定到具体属性和 hard-coded Error 字符串。您需要从样式和控件模板外部传递它们。

您对 DataTrigger 的比较可以封装在一个值转换器中,该转换器 returns 一个布尔值,用于比较任何边界 属性 (PosError) 与固定作为参数传递的值 (Error)。

public class ErrorComparisonToBoolConverter : IValueConverter
{
   public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
   {
      return value != null && parameter != null && value.Equals(parameter);
   }

   public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
   {
      throw new InvalidOperationException();
   }
}

DataTrigger中,我们不再绑定一个具体的属性,而是ToolTipTag,这是一个通用的属性 ].

Gets or sets an arbitrary object value that can be used to store custom information about this element.

我们假设比较已经为我们完成并且 Tag 只包含结果 truefalse。这简化了 DataTrigger 并且对 PosError 的依赖性消失了。

接下来就可以去掉ToolTip里面的TextBlock了。 ToolTip is a ContentControl 并公开一个 Content 属性。此内容使用 ControlTemplate 内的 ContentPresenter 自动显示。对 PosExtreme 的依赖也消失了。

将样式移出范围内的资源字典并创建一个转换器实例。

<local:ErrorComparisonToBoolConverter x:Key="ErrorComparisonToBoolConverter"/>
<Style x:Key="MyToolTipStyle" TargetType="{x:Type ToolTip}">
   <Style.Triggers>
      <DataTrigger Binding="{Binding Tag, RelativeSource={RelativeSource Self}}" Value="True">
          <DataTrigger.Setters>
              <Setter Property="Foreground">
                  <Setter.Value>
                      <LinearGradientBrush StartPoint="0 0" EndPoint="0 1">
                          <GradientStop Color="#F08080" Offset="0"/>
                          <GradientStop Color="#F04080" Offset="1"/>
                      </LinearGradientBrush>
                   </Setter.Value>
               </Setter>
           </DataTrigger.Setters>
       </DataTrigger>
   </Style.Triggers>
    <Setter Property="FontSize" Value="16"/>
    <Setter Property="HasDropShadow" Value="True" />
    <Setter Property="OverridesDefaultStyle" Value="true" />
    <Setter Property="Foreground">
        <Setter.Value>
            <LinearGradientBrush StartPoint="0 0" EndPoint="0 1">
                <GradientStop Color="#10F080" Offset="0"/>
                <GradientStop Color="#10B080" Offset="1"/>
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ToolTip">
                <Border 
                    CornerRadius="3"
                    BorderThickness="1"
                    Background="#CF001233"
                    SnapsToDevicePixels="True"
                    Width="{TemplateBinding Width}"
                    Height="{TemplateBinding Height}">
                    <Border.Style>
                        <Style TargetType="{x:Type Border}">
                            <Setter Property="BorderBrush">
                                <Setter.Value>
                                    <LinearGradientBrush StartPoint="0 0" EndPoint="0 1">
                                        <GradientStop Color="#A0A0F0" Offset="0"/>
                                        <GradientStop Color="#8080F0" Offset="1"/>
                                        <LinearGradientBrush.RelativeTransform>
                                            <RotateTransform CenterX="0.5" CenterY="0.5"/>
                                        </LinearGradientBrush.RelativeTransform>
                                    </LinearGradientBrush>
                                </Setter.Value>
                            </Setter>
                            <Style.Triggers>
                                <EventTrigger RoutedEvent="Border.Loaded">
                                    <BeginStoryboard>
                                        <Storyboard RepeatBehavior="Forever">
                                            <DoubleAnimation 
                                                From="359"
                                                To="0"
                                                Duration="00:00:2" 
                                                Storyboard.TargetProperty="(Border.BorderBrush).(Brush.RelativeTransform).(RotateTransform.Angle)"/>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </EventTrigger>
                            </Style.Triggers>
                        </Style>
                    </Border.Style>
                    <ContentPresenter Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

您现在可以重用该样式并将 PosExtreme 或任何其他 属性 绑定到 ToolTipContent 并将错误 [​​=73=] 绑定到 TagTag 绑定使用值转换器将绑定值与作为 CommandParameter.

传递的预期错误代码进行比较
<TextBox.ToolTip>
    <ToolTip Style="{StaticResource MyToolTipStyle}"
             Content="{Binding PosExtreme}"
             Tag="{Binding PosError, ConverterParameter=Error, Converter={StaticResource ErrorComparisonToBoolConverter}}">
    </ToolTip>
</TextBox.ToolTip>

备注

  • 该解决方案使用 Tag 属性 传播错误 属性。在您的示例中,它可以工作,但是如果您需要在样式或控件模板中绑定更多属性,则必须为每个可以绑定的属性创建附加属性,而不是 Tag。对于单个属性,Tag很方便。
  • 您还可以创建一个自定义 ToolTip 控件,它公开样式和控件模板中使用的属性的依赖属性而不是附加属性,并在其中进行比较。
  • 根据数据项的实现方式,如果有意义,您可以通过公开布尔值 属性 完全消除转换器。