I’m getting an exception in my C#/.NET application that reads:
‘CommandCoverter’ is unable to convert ‘MyNamespace.MyDerivedFromICommandSubclass’ to ‘System.String’.
What I’m doing is fairly straight forward, as described by the MSDN ICommand documentation:
public class MyDerivedFromICommandSubclass : ICommand
{
// Implement interface
...
}
I have a FlowDocument with a Hyperlink on it. The Hyperlink is allowed to have a Command Property, which I set to my derived ICommand so that when the link is clicked, my custom action gets performed.
That part works.
Here’s where I get into trouble: if I select the hyperlink and right-click Copy (or press Control-C).
Instantly the .NET framework throws a System.NotSupportedException with the exception detail above. The stack trace shows:
at System.ComponentModel.TypeConverter.GetConvertToException(Object value, Type destinationType)
at System.Windows.Input.CommandConverter.ConvertTo(ITypeDescriptorContext context, CultureInfo culture, Object value, Type destinationType)
At this point I resorted to Red Gate’s free .NET Reflector and looked at the source code to ConvertTo:
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == null) // We know it isn't, it's System.String
{
throw new ArgumentNullException("destinationType"); // We don't see this exception
}
if (destinationType == typeof(string)) // It is, so control passes in
{
if (value == null) // It isn't, so this condition is skipped
{
return string.Empty; // Confirmed we don't get this return value
}
RoutedCommand command = value as RoutedCommand;
if (((command != null) && (command.OwnerType != null) && IsKnownType(command.OwnerType))
{ // Is a user-defined ICommand a known type? Doubtful. This gets skipped.
return command.Name; // Confirmed we don't get this return value
}
// It has to fall through then if no return is done!
}
throw base.GetConvertToException(value, destinationType); // BOOM!
// value is my custom ICommand and destinationType is System.String
}
So the question then becomes, as all of this happens inside of .NET, am I doing something wrong, and if so, what? Or, is this a .NET bug, and if so, is there a work around?
Thanks for any help.
A fantastic description of ICommand resides in this blog entry by SkySigal, though I needed Google’s Cache due to blog configuration issues at the time. Unfortunately, the end of the article where this problem is addressed is a little ambiguous in its wording about whether the ICommand should be static or non-static.
Turns out, however, there was an article on dotnet mania talking about how copying a hyperlink with a custom command will crash an application.
Seems this bug has been in .NET since 2007, at least, and that the problem is the code explicitly checking for “known commands,” just as the Reflector analysis above showed.
.NET wants to serialize the command along with its parent object, and that’s where the problem comes in. The article’s solution involves creating a helper object, which is ignored by the serialization process, which does the same thing as the command.
becomes
with some backing code inside the myns namespace’s HyperlinkHelper class as a property named Command. It’s clever trickery, and ought to be shamefully unnecessary.
Hats off to Eric Burke for figuring this one out.