Jim Rogers

Lives in Baton Rouge, LA, with two dogs, one cat, and one lovely wife. I'm a lead developer for GCR Incorporated.

Katrin and Jim

Month List

Does My Type Subclass a Generic Type?

by Jim Mar 26, 2009 6:42 PM

It’s trivially easy to check if your type subclasses some other type with Type.IsSubclassOf(). But what if that subclass is a generic one? IsSubclassOf() doesn’t work for that.

Enter the IsSubclassOfGeneric() extension method. I’m pretty new to extension methods, and haven’t found a lot of practical uses for then yet, but I like this one. We’re using reflection and generics a lot in my current project and this has been nice in a couple of places…

/// <summary> 
/// Check if a type subclasses a generic type 
/// </summary> 
/// <param name="genericType">The suspected base class</param> 
/// <returns>True if this is indeed a subclass of the given generic type</returns> 
public static bool IsSubclassOfGeneric(this Type type, Type genericType)
{
    Type baseType = type.BaseType;

    while (baseType != null)
    {
        if (baseType.IsGenericType && 
            baseType.GetGenericTypeDefinition() == genericType)
            return true;
        else baseType = baseType.BaseType;
    }
    return false;
}

Tags:

Code

WPF Validation Exceptions

by Jim Mar 15, 2009 5:01 PM

The MSDN binding validation sample would have you bind your validation error messages like so:

<Trigger Property="Validation.HasError" Value="true">
<
Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</
Trigger>

This code will flood your output window with exceptions – and if you have the “break when exception is thrown” option turned on, you'll be doing a whole lot of stepping through these.

A first chance exception of type 'System.FormatException' occurred in mscorlib.dll A first chance exception 
of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll A first chance exception of type
'System.Reflection.TargetInvocationException' occurred in mscorlib.dll System.Windows.Data Error: 16 :
Cannot get 'Item[]' value (type 'ValidationError') from '(Validation.Errors)' (type 'ReadOnlyObservableCollection`1').
BindingExpression:Path=(0).[0].ErrorContent; DataItem='TextBox' (Name='textBox1'); target element is 'TextBox'
(Name='textBox1'); target property is 'ToolTip' (type 'Object')

TargetInvocationException:'System.Reflection.TargetInvocationException: Exception has been thrown by the target
of an invocation. ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and
less than the size of the collection.
Parameter name: index at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument,
ExceptionResource resource)
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List`1.get_Item(Int32 index)
at System.Collections.ObjectModel.Collection`1.get_Item(Int32 index)
at System.Collections.ObjectModel.ReadOnlyCollection`1.get_Item(Int32 index)
--- End of inner exception stack trace ---
. . . at MS.Internal.Data.PropertyPathWorker.RawValue(Int32 k)'

The problem appears to be that when the error is cleared (and HasError is false,) the binding is trying to evaluate again anyway. So the index of zero is out of range.

Josh Smith has a workaround for this that involves a content and data presenter. It’s a little heavy for my taste.

However that solution and this post detailing Microsoft’s failure to fix this known issue started me on the following solution:

<Setter Property="ToolTip" 
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors).CurrentItem,
Converter={StaticResource ValidationErrorConverter}}"/>

The CurrentItem property is null if there is nothing in the collection – so no exceptions are thrown evaluating it if there are no errors. It is an instance of ValidationError, however, and doesn't have a useful ToString() override. So I'm using an IValueConverter to get the error message. Here it is in its entirety:

/// <summary> 
///
Helps with avoiding of exceptions when setting a tooltip to the validation error
/// </summary>
/// <remarks>
///
Bind to Path=(Validation.Errors).CurrentItem, and use this converter
/// </remarks>
public class ValidationErrorConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { var error = value as ValidationError; // If we have an error, return its content if (error != null) return error.ErrorContent; else return ""; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { // Can't convert back to a ValidationError throw new Exception("The method or operation is not implemented."); } }

Tags:

Code