创建一个ToolTip,在WPF 4.5中使用INotifyDataErrorInfo显示控件的所有Validation.Errors

Mat*_*llo 5 c# wpf inotifydataerrorinfo .net-4.5

我有多个控件,包括TextBox和ComboBox,我希望所有控件都显示一个ToolTip,其中包含Validation.Errors集合中包含的所有错误.如果可能的话,我希望他们都能分享一种共同的风格,这就是我的努力.我确信我在ToolTip setter中的绑定有问题,但我无法弄清楚是什么.我在INotifyDataErrorInfo实现中返回一个Error对象,该对象指定错误的严重性(错误或警告).

我希望有一个适用于Window中所有控件的样式,它将显示一个ToolTip,其中包含该控件的所有错误和警告的列表.错误应显示为红色,警告显示为黄色.这是我提出的风格:

        <Style TargetType="FrameworkElement">
        <Setter Property="ToolTip">
            <Setter.Value>
                <ItemsControl ItemsSource="{Binding Path=(Validation.Errors), RelativeSource={RelativeSource Self}}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding ErrorContent.ErrorMessage}">
                                <TextBlock.Style>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="Foreground" Value="Red"/>
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
                                                             Value="{x:Static local:ErrorType.Warning}">
                                                <Setter Property="Foreground" Value="Yellow"/>
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </TextBlock.Style>
                            </TextBlock>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <DataTrigger Binding="{Binding Path=(Validation.HasError)}" Value="True">
                <Setter Property="ToolTip">
                    <Setter.Value>
                        <ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}">
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <TextBlock Text="{Binding ErrorContent.ErrorMessage}">
                                        <TextBlock.Style>
                                            <Style TargetType="TextBlock">
                                                <Setter Property="Foreground" Value="Red"/>
                                                <Style.Triggers>
                                                    <DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
                                                             Value="{x:Static local:ErrorType.Warning}">
                                                        <Setter Property="Foreground" Value="Yellow"/>
                                                    </DataTrigger>
                                                </Style.Triggers>
                                            </Style>
                                        </TextBlock.Style>
                                    </TextBlock>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </Setter.Value>
                </Setter>
            </DataTrigger>
        </Style.Triggers>
    </Style>
Run Code Online (Sandbox Code Playgroud)

我已经尝试更改RelativeSource以在AncestorLevel 1和2处搜索AncestoryType of Control.这似乎都不起作用.

我将这个样式基于我用于ErrorTemplate的ControlTemplate,它做了几乎相同的事情:它根据错误严重程度显示红色或黄色边框,并显示一个ToolTip,就像我想要对控件上的ToolTip做的那样本身.我确定它与我的绑定有关,因为ErrorTemplate自动将其DataContext设置为Validation.Errors集合,这使得为ItmesCollection绑定ItemsSource变得容易.风格的工具提示没有这样的运气.这是我用于ErrorTemplate的工作ControlTemplate:

        <ControlTemplate x:Key="ErrorTemplate">
        <Border BorderThickness="1">
            <AdornedElementPlaceholder Name="ElementPlaceholder"/>
            <Border.Style>
                <Style TargetType="Border">
                    <Setter Property="BorderBrush" Value="Red"/>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding ElementName=ElementPlaceholder, Path=AdornedElement.(Validation.Errors)[0].ErrorContent.ErrorSeverity}"
                                         Value="{x:Static local:ErrorType.Warning}">
                            <Setter Property="BorderBrush" Value="Yellow"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Border.Style>
            <Border.ToolTip>
                <ItemsControl ItemsSource="{Binding}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding ErrorContent.ErrorMessage}">
                                <TextBlock.Style>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="Foreground" Value="Red"/>
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
                                                             Value="{x:Static local:ErrorType.Warning}">
                                                <Setter Property="Foreground" Value="Yellow"/>
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </TextBlock.Style>
                            </TextBlock>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Border.ToolTip>
        </Border>
    </ControlTemplate>
Run Code Online (Sandbox Code Playgroud)

谁能给我任何建议?

小智 7

这可以更容易实现.

如果您将绑定写入"Tooltip",如上所示:

<Trigger Property="Validation.HasError" Value="True">
      <Setter Property="ToolTip"
              Value="{Binding RelativeSource={RelativeSource Self},  Path=(Validation.Errors), Converter={StaticResource ErrorCollectionConverter}}">
      </Setter>
</Trigger>
Run Code Online (Sandbox Code Playgroud)

Binding"奇迹般地"实际上将自己重新绑定到工具提示的"PlacementTarget".因此对于控制它是附着的.

如果您需要显示完整的项目列表,您可以执行以下操作:

<Trigger Property="Validation.HasError" Value="True">
      <Setter Property="ToolTip">
          <Setter.Value>
               <ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}">
                   <ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}" DisplayMemberPath="ErrorContent" />
               </ToolTip>
          </Setter.Value>
      </Setter>
</Trigger>
Run Code Online (Sandbox Code Playgroud)

您甚至可以删除Tooltip对象并直接从ItemsControl绑定到PlacementTarget.然后在ItemsControl上通过AncestorType使用Tooltip作为RelativeSource.

希望这可以帮助 :)


Mat*_*llo 5

在试图解决这个问题很长一段时间之后,我终于偶然发现MSDN论坛上的一篇帖子让我走上了正确的道路.首先,我需要为我想要的每个TargetType指定样式并将它们基于原始样式.其次,我意识到问题不在于我的绑定,而在于绑定的集合没有被更新.我不知道为什么我的ListBox/ItemsControl在XAML中指定时没有更新,但如果你在转换器中指定它,它确实有效.这是我的新风格:

        <Style TargetType="Control" x:Key="ErrorToolTip">
        <Style.Resources>
            <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <TextBlock Text="{Binding ErrorContent.ErrorMessage}"
                                       Background="Transparent">
                                <TextBlock.Style>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="Foreground" Value="Red"/>
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
                                                         Value="{x:Static local:ErrorType.Warning}">
                                                <Setter Property="Foreground" Value="Orange" />
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </TextBlock.Style>
                            </TextBlock>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Style.Resources>
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="True">
                <Setter Property="ToolTip"
                        Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors), Converter={StaticResource ErrorCollectionConverter}}">
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>
    <Style TargetType="TextBox" BasedOn="{StaticResource ErrorToolTip}"/>
    <Style TargetType="ComboBox" BasedOn="{StaticResource ErrorToolTip}"/>
Run Code Online (Sandbox Code Playgroud)

这是我的转换器功能:

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null) return null;
        return new ListBox
        {
            ItemsSource = (ReadOnlyObservableCollection<ValidationError>) value,
            BorderThickness = new Thickness(0),
            Background = Brushes.Transparent
        };
    }
Run Code Online (Sandbox Code Playgroud)

我希望这对那些有同样问题的人有帮助.如果有人知道为什么会有这么大的差异,我很想知道.