当前位置: 首页 > 知识库问答 >
问题:

创建显示所有验证的工具提示。WPF 4.5中使用INotifyDataErrorInfo的控件的错误

辛意智
2023-03-14

我有多个控件,包括一个文本框和一个组合框,我希望所有这些控件都显示一个工具提示,其中包含 Validation.Errors 集合中包含的所有错误。如果可能的话,我希望他们都分享一种共同的风格,这就是我正在尝试的。我确信我在工具提示设置器中的绑定做错了什么,但我无法弄清楚是什么。我在 INotifyDataErrorInfo 实现中返回一个 Error 对象,该对象指定错误的严重性(错误或警告)。

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

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

我尝试更改相对源以搜索祖先级别 1 和 2 的祖先故事控件类型。这些似乎都行不通。

我的样式基于一个用于ErrorTemplate的ControlTemplate,它做了几乎相同的事情:它根据错误的严重程度显示红色或黄色边框,并显示一个工具提示,就像我希望在控件本身上为工具提示所做的那样。我确信这与我的绑定有关,因为ErrorTemplate自动将其DataContext设置为验证。Errors集合,这使得为ItmesCollection绑定ItemsSource变得很容易。该样式的工具提示就没有这样的运气了。以下是我在错误模板中使用的工作控制模板:

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

有人能给我一些建议吗?

共有3个答案

谢同化
2023-03-14

这只是我使用的Matts答案的一个更简化的版本。它仅适用于TextBox类型的控件,并且不使用错误严重性。当我需要在用户输入的目录路径的上下文中显示一个或多个错误时,我使用了这种情况。与Matts答案相反,我使用DisplayMemerPath="Error Content"直接在转换器中访问错误。


TextBox的样式,当附加属性Validation. HasError为真时,它显示工具提示:

<UserControl.Resources>
    <ui:ErrorCollectionConverter x:Key="ErrorCollectionConverter"></ui:ErrorCollectionConverter>
    <Style TargetType="TextBox">
        <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>
</UserControl.Resources>

我的“目录”TextBox隐式使用样式:

<TextBox Text="{Binding Directory, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}"></TextBox>

直接访问<code>ErrorContent</code>属性的值转换器:

internal class ErrorCollectionConverter : IValueConverter
{
    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,
            DisplayMemberPath = "ErrorContent"
        };
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}   
水恩
2023-03-14

经过一段时间的尝试,我终于在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}"/>

这是我的转换器函数

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

我希望这对其他有我同样问题的人有帮助。如果有人知道为什么这会产生如此大的差异,我很想知道。

沈子实
2023-03-14

这可以更容易地实现。

如果您像上面那样编写“工具提示”的绑定:

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

绑定“奇迹般地”实际上将自身重新绑定到工具提示的“放置目标”。因此,它被附加到控件上。

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

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

您甚至可以删除Tooltip对象并直接从ItemsControl绑定到PlacementTarget。然后只需通过ItemsControl上的AncestorType将Tooltip用作RelativeSource。

希望这有帮助:)

 类似资料:
  • 问题内容: 我有一个JComponent可以自己绘制各种形状。我检测到鼠标何时进入这些形状之一,并相应地更改工具提示。 我遇到的问题是: 用户在形状上跟踪鼠标时,工具提示不会跟随鼠标。它停留在最初设置的位置,然后仅在其他形状更改工具提示时才跳转。 工具提示大约需要一秒钟的时间,但我希望它立即显示。 有人可以建议一种无需编写自定义工具提示机制即可获得这些行为的方法吗? 问题答案: 看一下ToolTi

  • 问题内容: 我想为工具提示创建一个自定义CSS类,该类将包裹长度超过25-30的字符串。通常这样长的文本不适合tootltip文本区域。 而且是否有使用[工具提示ui.bootstrap.tooltip)进行此操作?就像使用自定义CSS类来获取所需的输出。 这是简单的CSS工具提示 这是相同的代码片段: 问题答案: CSS解决方案 对于眼前的问题有一个非常简单的解决方案。我基本上添加的是以下CSS

  • 我已经使用FullCalendar配置有一段时间了,但我已经到了一个无法理解的地步。我希望启用当最终用户将鼠标悬停在事件上时显示的工具提示。我想在活动的工具提示中提供一些进一步的信息,例如电话联系号码等。 我尝试了许多不同的选择,我能够找到 例如,下面的链接列表 完整日历事件弹出窗口 http://jsfiddle.net/m54g5aen/ Fullcalendar/eventdidmount-

  • 我使用的是带有2条线的图表js折线图。我有7个x轴数据点。我只想显示第一个、第二个和最后一个数据点。但我想在工具提示中显示每个数据点。目前,我只在 x 轴标签中列出 1、2 和 7,因此工具提示在 2 上正确显示,但在其他区域当然什么都没有。那么有没有办法不在x轴上显示特定的数据点(但在代码中仍然有用于工具提示的数据)?(另外,这是一个非常简化的例子,说明我正在尝试做什么) 谢谢。

  • 本文向大家介绍C#验证码的创建与使用示例,包括了C#验证码的创建与使用示例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#验证码的创建与使用方法。分享给大家供大家参考,具体如下: 1、C#创建验证码 ① 创建获取验证码页面(ValidateCode.aspx) ② 编写获取验证码代码(ValidateCode.aspx.cs) 2、验证码的使用 ① 验证码的前段显示代码 ② 创建验证码

  • 我在我的类的构造函数中使用了这段代码。 当鼠标进入时,println语句会打印到控制台,但其他两个工具提示方法不会显示相关的工具提示。这里的combobox是swing combobox的一个实例字段。settooltip方法不显示工具提示的原因是什么?