Alan
Alan

Reputation: 7951

XAML subclass type declaration designer error

I have a simple problem with the designer.. I'm trying to bind the ItemsSource of a DataGridComboBoxColumn to a list of Enum values. It works, the code compiles and executes just fine. However, the designer says "Problem loading" and will not load properly. If I click "Reload the designer" it shows an error in the Error List. I'm using VS2010.

<ObjectDataProvider x:Key="myEnum"
        MethodName="GetValues"
        ObjectType="{x:Type core:Enum}">
<ObjectDataProvider.MethodParameters>
    <x:Type Type="data:ParentClass+MyEnum" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

This works fine when the application executes. However, in the designer it says:

Error 5 Type 'data:ParentClass+MyEnum' was not found.

I'm not sure where I ever came across the Class+Subclass syntax (instead of Class.Subclass) for XAML or why it is necessary, but it would seem the designer should work if the code works?! This kills all my design-time support for my entire window, which is not good if I want to see what changes look like at design time

Update Alright, some more information: First off, the + syntax comes from the Type.GetType(String) method and you can see its formats there.

However, the System.Windows.Markup.TypeExtension uses the IXamlTypeResolver service to resolve the type. From reflector, we can see this:

IXamlTypeResolver service = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
this._type = service.Resolve(this._typeName);

And from what I understand, the designer uses an entirely different implementation of this service than the runtime?! I haven't located the implementations.

I believe that I could write my own "TypeExtension" class and just do return Type.GetType(typeName). I'm still curious if this is just a bug or a way to make it work.

Update2

I created my own TypeExtension class but it did not help. For some reason Type.GetType() fails to resolve my Enum through the designer (but not runtime)

public class CreateTypeExtension : TypeExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (this.Type == null)
        {
            if (this.TypeName == null)
            {
                throw new InvalidOperationException();
            }

            this.Type = Type.GetType(TypeName);

            if (this.Type == null)
            {
                throw new InvalidOperationException("Bad type name");
            }
        }

        return this.Type;
    }
}

I was passing it

<comm:CreateType TypeName="Company.Product.Class+Enum,Company.Assembly" />

Again, works at runtime and is fully qualified yet it doesn't work at design time.

Upvotes: 3

Views: 466

Answers (1)

Alan
Alan

Reputation: 7951

Alright, I realized that when it didn't work after Update2 that the error message was much more specific than what I was throwing. Therefore, it wasn't using my override. I modified it to not extend TypeExtension and instead MarkupExtension and now it works.

public class CreateTypeExtension : MarkupExtension
{
    public Type Type { get; set; }
    public String TypeName { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (this.Type == null)
        {
            if (this.TypeName == null)
            {
                throw new InvalidOperationException();
            }

            this.Type = Type.GetType(TypeName);

            if (this.Type == null)
            {
                throw new InvalidOperationException("Bad type name");
            }
        }

        return this.Type;
    }
}

And you can use any format available in the documentation for Type.GetType, but you can no longer use the XAML prefixes (unless you implement this yourself)

<comm:CreateType TypeName="Company.Product.Class+Enum,Company.Assembly" />

Upvotes: 1

Related Questions