44

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.

    <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

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

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

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

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

// 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;
    }
}
Mike B
  • 2,592
  • 3
  • 33
  • 46
  • Well it has been a week with no responses on a question I had assumed was somthing silly on my part. Does anyone have a suggestion on where to research or for additional information for me to post on my problem? – Mike B Feb 21 '10 at 01:48

6 Answers6

131

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:

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.

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

update so 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)

<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

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

Path=(Validation.Errors)/ErrorContent
Martin
  • 16,093
  • 1
  • 29
  • 48
Nathan Tregillus
  • 6,006
  • 3
  • 52
  • 91
  • Thanks for this correction! I had the same problem and now the ugly messages in the output window disappeared. – Slauma Feb 04 '11 at 11:46
  • Thanks for the tip on `.CurrentItem` instead of `[0]`! That error in the console has been bothering me. – Matt Jul 15 '11 at 19:30
  • 3
    @NathanTregillus Excellent tip. On the ControlTemplate, I had to use `ToolTip="{Binding Path=/ErrorContent}"` otherwise I just got a class name inside the tooltip. – mdisibio Dec 20 '12 at 05:03
  • Beautiful. Had the same ussue and .CurrentItem instead of [0] fixed the issue for me. However, I'm working with a large app and the validation I'm using is used throughout my entire app. Is there any fallback of using the .CurrentItem over [0] or that it something else could fault from changing this? Thanks in advance! – justin peterson Jan 03 '13 at 23:03
  • Not that I am aware, unless there are multiple validation messages for the one field. I am not sure how the order of errors in the collection will be interpreted by your app. – Nathan Tregillus Jan 08 '13 at 16:41
  • I just noticed I never followed up on my earlier comment. THis was a great answer and did the trick... Thanks – Mike B Apr 19 '13 at 15:11
  • For some reason, I can't use the `.CurrentItem` any suggestions? – Noctis May 03 '14 at 07:48
  • 1
    Cool! You should mention that Visual Studio presents a warning stating that `ErrorContent` is unkown on `ObservableCollection`. Works anymay! – Alexander Schmidt May 26 '16 at 16:34
  • Thanks this was really useful. – Billy Jake O'Connor Dec 13 '18 at 22:15
  • 3
    @NathanTregillus Thanks so much for your tip! After days of ...! **BUT** please update your post, It seems using `/` instead of `.CuttentItem` is correct for now! @Alexander It seems `ObservableCollection` working these days too! I tested on both `IEnumerable` and `ObservableCollection`. Thanks for your Tip too anyway! – MRK Apr 07 '19 at 07:57
18

I think this is the best way:

Path=(Validation.Errors)/ErrorContent

/ is actually equal to CurrentItem by @Nathan

In my case, CurrentItem is a no go.

Altiano Gerung
  • 824
  • 2
  • 15
  • 28
2

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

djamwal
  • 21
  • 2
2

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.

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

Noctis
  • 11,507
  • 3
  • 43
  • 82
David
  • 21
  • 1
2

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

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

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

<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"
                    >
user8128167
  • 6,929
  • 6
  • 66
  • 79
2

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.

<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>
bbedson
  • 133
  • 1
  • 8