views:

644

answers:

3

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

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

djamwal
A: 

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.

David