为啥 WPF 样式在工具提示中显示验证错误适用于文本框但对组合框无效?

Posted

技术标签:

【中文标题】为啥 WPF 样式在工具提示中显示验证错误适用于文本框但对组合框无效?【英文标题】:Why does WPF Style to show validation errors in ToolTip work for a TextBox but fails for a ComboBox?为什么 WPF 样式在工具提示中显示验证错误适用于文本框但对组合框无效? 【发布时间】:2011-01-16 15:59:09 【问题描述】:

我正在使用典型的样式将验证错误显示为来自 IErrorDataInfo 的文本框的工具提示,如下所示,它工作正常。

    <Style TargetType="x:Type TextBox">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="ToolTip"
                Value="Binding RelativeSource=RelativeSource Self,
            Path=(Validation.Errors)[0].ErrorContent"/>
            </Trigger>
        </Style.Triggers>
    </Style>

但是当我尝试为这样的 ComboBox 做同样的事情时,它失败了

    <Style TargetType="x:Type ComboBox">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="ToolTip"
                Value="Binding RelativeSource=RelativeSource Self,
            Path=(Validation.Errors)[0].ErrorContent"/>
            </Trigger>
        </Style.Triggers>
    </Style>

我在输出窗口中得到的错误是:

System.Windows.Data 错误:17:无法从“(Validation.Errors)”(类型“ReadOnlyObservableCollection`1”)获取“Item[]”值(类型“ValidationError”)。 BindingExpression:Path=(0)[0].ErrorContent; DataItem='ComboBox' (Name='ownerComboBox');目标元素是'ComboBox'(名称='ownerComboBox');目标属性是“工具提示”(类型“对象”)ArgumentOutOfRangeException:“System.ArgumentOutOfRangeException:指定的参数超出了有效值的范围。参数名称:索引”

奇怪的是,如果我更改任何 ComboBox 值,当我关闭窗口时它也会尝试进行无效的数据库更改(这也是发生绑定错误的时候)!!!

无法将值 NULL 插入到列“EmpFirstName”、表“OITaskManager.dbo.Employees”中;列不允许空值。插入失败。 声明已终止。

只需将样式注释掉,一切就完美了。我该如何解决这个问题?

以防万一有人需要它,组合框的 xaml 之一如下:

<ComboBox ItemsSource="Binding Path=Employees" 
                  SelectedValuePath="EmpID"                       
                  SelectedValue="Binding Path=SelectedIssue.Employee2.EmpID,
                     Mode=OneWay, ValidatesOnDataErrors=True" 
                  ItemTemplate="StaticResource LastNameFirstComboBoxTemplate"
                  Height="28" Name="ownerComboBox" Width="120" Margin="2" 
                  SelectionChanged="ownerComboBox_SelectionChanged" />


<DataTemplate x:Key="LastNameFirstComboBoxTemplate">
    <TextBlock> 
         <TextBlock.Text> 
             <MultiBinding StringFormat="1, 0" > 
                   <Binding Path="EmpFirstName" /> 
                   <Binding Path="EmpLastName" /> 
             </MultiBinding>
         </TextBlock.Text>
    </TextBlock>
</DataTemplate>

SelectionChanged:(我确实计划在不久之后实施命令,但由于这是我的第一个 WPF 项目,我还没有完成完整的 MVVM。我正在尝试以中小型的方式进行操作)

// This is done this way to maintain the DataContext Integrity 
// and avoid an error due to an Object being "Not New" in Linq-to-SQL
private void ownerComboBox_SelectionChanged(object sender, 
                                            SelectionChangedEventArgs e)

    Employee currentEmpl = ownerComboBox.SelectedItem as Employee;
    if (currentEmpl != null && 
        currentEmpl != statusBoardViewModel.SelectedIssue.Employee2)
    
        statusBoardViewModel.SelectedIssue.Employee2 = currentEmpl;
    

【问题讨论】:

好吧,已经有一周没有回答我认为对我来说有点愚蠢的问题了。有没有人建议我在哪里研究或提供更多信息让我发布我的问题? 【参考方案1】:

您收到此错误是因为当您验证发现没有问题时,Errors 集合返回没有项目,并且以下绑定逻辑失败:

Path=(Validation.Errors)[0].ErrorContent"

您正在通过特定索引访问验证集合。我目前正在研究替换此文本的 DataTemplate 建议。

我喜欢微软在他们的标准验证模板示例中列出了这一点。

更新 所以将上面的代码替换成下面的代码,绑定逻辑就会知道如何处理空的validationresult集合:

Path=(Validation.Errors).CurrentItem.ErrorContent"

(以下 xaml 被添加为评论)

<ControlTemplate x:Key="ValidationErrorTemplate" TargetType="Control">
    <StackPanel Orientation="Horizontal">
        <TextBlock Foreground="Red" FontSize="24" Text="*" 
                   ToolTip="Binding .CurrentItem">
        </TextBlock>
        <AdornedElementPlaceholder>
        </AdornedElementPlaceholder>
    </StackPanel>
</ControlTemplate>

2019 年更新

目前,使用的正确路径语法是:

Path=(Validation.Errors)/ErrorContent

【讨论】:

感谢您的更正!我遇到了同样的问题,现在输出窗口中丑陋的消息消失了。 感谢.CurrentItem 而不是[0] 的提示!控制台中的错误一直困扰着我。 @NathanTregillus 很好的提示。在 ControlTemplate 上,我必须使用 ToolTip="Binding Path=/ErrorContent" 否则我只会在工具提示中得到一个类名。 酷!您应该提到 Visual Studio 会显示一条警告,指出 ErrorContentObservableCollection 上是未知的。随时可用! @NathanTregillus 非常感谢您的提示!经过几天...! 但是请更新您的帖子,现在使用/ 而不是.CuttentItem 似乎是正确的! @Alexander 这几天似乎ObservableCollection 也在工作!我在IEnumerableObservableCollection 上都进行了测试。无论如何也感谢您的提示!【参考方案2】:

我认为这是最好的方法:

Path=(Validation.Errors)/ErrorContent

/ 实际上等于@Nathan 的CurrentItem

就我而言,CurrentItem 是不行的。

【讨论】:

这个问题是在 2010 年。从那以后情况发生了变化 @AltianoGerung 非常感谢更新提示!是的,我同意有人也应该更新正确答案!【参考方案3】:

如here 所述,尝试使用转换器转换为多行字符串

【讨论】:

【参考方案4】:

就我而言,当我尝试应用 @Nation Tregillus' 解决方案时遇到此异常:

无法解析类型数据上下文中的属性“CurrentItem” 'System.Collections.ObjectModel.ReadOnlyObservableCollection'

所以我改用@Altiano Gerung 的解决方案,我的代码最终变成了:

<ControlTemplate x:Key="ValidationErrorTemplate">
    <DockPanel Margin="5,0,36,0">
        <StackPanel Orientation="Horizontal" VerticalAlignment="Top" DockPanel.Dock="Right"
                    Margin="5,0,36,0"
                    ToolTip="Binding ElementName=ErrorAdorner, Path=AdornedElement.(Validation.Errors)/ErrorContent"
                    ToolTipService.ShowDuration="300000"
                    ToolTipService.InitialShowDelay="0"
                    ToolTipService.BetweenShowDelay="0"
                    ToolTipService.VerticalOffset="-75"
                    >

【讨论】:

【参考方案5】:

我在多个地方看到了您使用的代码,但我觉得这很奇怪

Path=(Validation.Errors)[0].ErrorContent

不会引发任何危险信号。但我也是 WPF 的新手,也许在每种情况下都能做到这一点有一些秘密。

与其尝试使用数组索引来索引可能为空的集合,不如添加一个转换器来返回列表中的第一个错误。

【讨论】:

【参考方案6】:

CurrentItem 对我也不起作用但是 @Nathtan 的答案适用于我有自定义文本框资源的情况。谢谢@Nathan,我花了一个小时来解决这个问题。

<Style.Triggers>
  <Trigger Property="Validation.HasError" Value="true">
    <Setter Property="ToolTip"
        Value="Binding RelativeSource=x:Static RelativeSource.Self,
        Path=(Validation.Errors)/ErrorContent" />
  </Trigger>
</Style.Triggers>

【讨论】:

以上是关于为啥 WPF 样式在工具提示中显示验证错误适用于文本框但对组合框无效?的主要内容,如果未能解决你的问题,请参考以下文章

Bootstrap 4 工具提示样式仅适用于第一部分

angular12表单错误提示不显示边框

为啥我的 CornerRadius 的 WPF 样式未在 Windows 7 中应用?

为啥输入验证码时明明输入正确 却显示错误

WPF数据验证

为啥 Visual Studio 显示错误,提示在类型 Window 中找不到 Windows.Resources?