I have a multitrigger, one of whose conditions is
<Condition Property="Validation.HasError"
Value="True"/>
Outside the trigger, I set the error template to null, and only in one of the trigger's setters do I have
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
But for some reason sometimes I still get an exception that the index is out of range, i.e. that I'm trying to access element 0 of an empty error collection.
This seems to happen with controls whose backing data I try to do something with, but I'm not sure of what's causing it to try to create the tooltip even without any errors.
EDIT: I've removed as much stuff as possible and the following is what is left. The exception arises when typing something into the data-bound textbox and then switching focus.
In App.xaml, under application resources
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError"
Value="True">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
In MainWindow.xaml.cs (this is the startup window)
public MainWindow()
{
InitializeComponent();
this.DataContext = new Bar();
}
In MainWindow.xaml, the relevant binding
<TextBox Text="{Binding Foo, ValidatesOnDataErrors=True}"/>
In Bar.cs
public sealed class Bar : IDataErrorInfo, INotifyPr开发者_JAVA百科opertyChanged
{
// Standard PropertyChanged, OnPropertyChanged removed
// Foo does have a backing field and notifies in the
// setter but those have been removed for brevity
public string Foo {get;set;}
public string Error
{
get { return ""; }
}
public string this[string columnName]
{
get
{
switch (columnName)
{
case "Foo":
if (string.IsNullOrEmpty(Foo))
return "The foo must not be empty.";
return "";
default:
throw new ArgumentException("columnName");
}
}
}
}
Instead of "Path=(Validation.Errors)[0].ErrorContent", use "Path=(Validation.Errors).CurrentItem.ErrorContent". No idea why this prevents it, considering that if there is an error there's no reason for the error collection to be null or empty or whatever, but it works.
Sometimes the errors collection will be null.
Add a converter to the Xaml
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors),
Converter={StaticResource ValidationErrorConverter}}"/>
Your converter should look like this:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ReadOnlyObservableCollection<ValidationError> errors = value as ReadOnlyObservableCollection<ValidationError>;
if (errors == null)
{
return String.Empty;
}
return errors.Count > 0 ? errors[0].ErrorContent : String.Empty;
}
精彩评论