C# 为什么 WPF 样式在 ToolTip 中显示验证错误适用于文本框,但无法用于组合框?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2260616/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-07 00:50:08  来源:igfitidea点击:

Why does WPF Style to show validation errors in ToolTip work for a TextBox but fails for a ComboBox?

c#wpfvalidationdata-bindingstyles

提问by Mike B

I am using a typical Style to display validation errors as a tooltip from IErrorDataInfo for a textbox as shown below and it works fine.

我正在使用典型的样式将验证错误显示为来自 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>

But when i try to do the same thing for a ComboBox like this it fails

但是当我尝试为这样的 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>

The error I get in the output window is:

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

System.Windows.Data Error: 17 : Cannot get 'Item[]' value (type 'ValidationError') from '(Validation.Errors)' (type 'ReadOnlyObservableCollection`1'). BindingExpression:Path=(0)[0].ErrorContent; DataItem='ComboBox' (Name='ownerComboBox'); target element is 'ComboBox' (Name='ownerComboBox'); target property is 'ToolTip' (type 'Object') ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.Parameter name: index'

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

Oddly it also attempts to make invalid Database changes when I close the window if I change any ComboBox values (This is also when the binding error occurs)!!!

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

Cannot insert the value NULL into column 'EmpFirstName', table 'OITaskManager.dbo.Employees'; column does not allow nulls. INSERT fails. The statement has been terminated.

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

Simply by commenting the style out everyting works perfectly. How do I fix this?

只需将样式注释掉,一切都完美无缺。我该如何解决?

Just in case anyone needs it one of the comboBox' xaml follows:

以防万一有人需要它,comboBox 的 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: (I do plan to implement commanding before long but, as this is my first WPF project I have not gone full MVVM yet. I am trying to take things in small-medium sized bites)

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

采纳答案by Nathan Tregillus

Your getting this error because when you validation finds that there are no issues, the Errors collection returns with no items, and the following binding logic fails:

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

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

you are accessing the validation collection by a specific index. I'm currently working on a DataTemplate Suggestion for replacing this text.

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

I love that Microsoft listed this in their standard example of a validation template.

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

updateso replace the code above with the following, and the binding logic will know how to handle the empty validationresult collection:

更新因此将上面的代码替换为以下代码,绑定逻辑将知道如何处理空的验证结果集合:

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

(following xaml was added as a comment)

(以下 xaml 被添加为评论)

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

Update in 2019

2019年更新

As of currently, the correct path syntax to use is:

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

Path=(Validation.Errors)/ErrorContent

回答by djamwal

Try the converter for converting to a multi-line string as described here

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

回答by David

I've seen the code you're using posted in multiple places, but it seems odd to me that

我已经看到您在多个地方发布的代码,但对我来说似乎很奇怪

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

doesn't raise any red flags. But I'm also new to WPF and perhaps there is some secret to making that work in every case.

不会引发任何危险信号。但我也是 WPF 的新手,也许在每种情况下都可以使用一些秘诀。

Rather than attempting to index a possibly empty collection with an array index, add a converter that returns the first error in the list.

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

回答by Altiano Gerung

I think this is the best way:

我认为这是最好的方法:

Path=(Validation.Errors)/ErrorContent

/is actually equal to CurrentItemby @Nathan

/实际上等于CurrentItem@Nathan

In my case, CurrentItemis a no go.

在我的情况下,CurrentItem是不行的。

回答by user8128167

In my case, I was getting this exception when I tried to apply @Nation Tregillus' solution:

就我而言,当我尝试应用@Nation Tregillus的解决方案时遇到了这个异常:

Cannot resolve property 'CurrentItem' in data context of type 'System.Collections.ObjectModel.ReadOnlyObservableCollection'

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

So I went with @Altiano Gerung's solution instead, where my code ended up being:

所以我改用 @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"
                    >

回答by bbedson

CurrentItem did not work for me either But @Nathtan's answer worked for my situation where I have a custom textBox resource. Thanks @Nathan I spent an hour on this.

CurrentItem 对我也不起作用但是@Nathtan 的回答适用于我有自定义 textBox 资源的情况。谢谢@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>