Convert ObjectInstance

Mar 2, 2010 at 11:54 PM
Edited Mar 17, 2010 at 10:53 PM

Michael,

As soon as I generalized CurrentItem on my navigation model I started getting this kind of errors:

System.Windows.Data Error: 22 : Cannot convert 'ViewModels.ClientViewModel' 
from type 'ObjectInstance`1' to type 'UpdateControls.XAML.Wrapper.ObjectInstance`1[ViewModels.EntityViewModelBase]'
for 'en-US' culture with default conversions; consider using Converter property of Binding.
NotSupportedException:'System.NotSupportedException: TypeConverter cannot convert from
UpdateControls.XAML.Wrapper.ObjectInstance`1[[ViewModels.ClientViewModel, Manager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].

It looks like it can't convert ObjectInstance<ChildClass> into ObjectInstance<BaseClass>, but I am not sure why it needs to do that.

Do you know why this might be?

Thank you!

Coordinator
Mar 4, 2010 at 5:54 PM

A while back I changed the code in ObjectProperty.WrapObject to produce wrappers based on the concrete type rather than the declared type of a property. More recently, I changed the code in ForView.Unwrap<T>() to use the IObjectInstance interface rather than a specific ObjectInstance<T> class. If you have the first change but not the second, ForView.Unwrap<EntityViewModelBase>() will throw an exception when unwrapping a ClientViewModel. But if you have the latest code it should not.

Is the exception that you are seeing coming from ForView.Unwrap, or some other part of the code?

 

Mar 4, 2010 at 6:04 PM

I used converters in the mean time, but let me try your latest code first.

The exception is coming from binding engine. Right here.

                <wpfToolkit:DataGrid 
                    SelectedItem="{Binding 
                                        Path=EntityNavigation.CurrentEntity,
                                        UpdateSourceTrigger=PropertyChanged, 
                                        Mode=TwoWay, 
                                        Converter={StaticResource ChildToParentEntityViewModelConverter}}"
                    .../>

In the converter I take ObjectInstance<ClientViewModel> and rewrap it as ObjectInstance<EntityViewModelBase> .

Thank you for your help!

Mar 4, 2010 at 10:32 PM

I tried latest build. But still get the same error.

So I am using this converter for now, which works.

    [ValueConversion(typeof(Object), typeof(Object))]
    class ChildToParentEntityViewModelConverter : IValueConverter
    {
        public Object Convert(Object value, System.Type targetType, Object parameter, System.Globalization.CultureInfo culture)
        {
            return value;
        }

        public Object ConvertBack(Object value, System.Type targetType, Object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is IObjectInstance)
            {
                object obj = (value as IObjectInstance).WrappedObject;
                if (obj is EntityViewModelBase)
                    return ForView.Wrap<EntityViewModelBase>(obj as EntityViewModelBase);
            }
            return value;
        }
    }

 

 

 

Mar 17, 2010 at 7:09 PM
Edited Mar 17, 2010 at 7:10 PM

I had to change converter after installing one of the updates. Will wait for covariance then...

    [ValueConversion(typeof(Object), typeof(Object))]
    class ChildToParentEntityViewModelConverter : IValueConverter
    {
        public Object Convert(Object value, System.Type targetType, Object parameter, System.Globalization.CultureInfo culture)
        {
            return value;
        }

        public Object ConvertBack(Object value, System.Type targetType, Object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is IObjectInstance)
            {
                object obj = (value as IObjectInstance).WrappedObject;
                if (obj is EntityViewModelBase)
                    return new ObjectInstance<EntityViewModelBase>((obj as EntityViewModelBase), App.Current.Dispatcher);
            }
            return value;
        }
    }

 

Coordinator
Mar 17, 2010 at 10:39 PM

This is a pretty nasty problem. I'm going to see if I can find another way to solve it. Perhaps the wrapper can treat the exposed properties as IObjectInstance rather than ObjectInstance<T>, so data binding can set them without regard to concrete type.

Mar 17, 2010 at 10:49 PM
Edited Mar 17, 2010 at 10:52 PM

Have you tried running it on .NET 4. 
RC is available and it supports covariance and contravariance for interfaces with generic types. Classes with generic types are still invariant, however.

MSDN says that such support existed since .NET 2.0 but only in MSIL. So theoretically it can be changed in there. I don't know how to automate it. Via post build commands or something.

http://msdn.microsoft.com/en-us/library/dd799517(VS.100).aspx

Starting with the .NET Framework version 2.0, the common language runtime supports variance annotations on generic type parameters. Prior to the .NET Framework 4, the only way to define a generic class that has these annotations is to use Microsoft intermediate language (MSIL), either by compiling the class with Ilasm.exe (MSIL Assembler) or by emitting it in a dynamic assembly.

Coordinator
Mar 17, 2010 at 11:42 PM
Edited Mar 17, 2010 at 11:42 PM

I have not tried this exact bug on .NET 4. In any case, it looks like I may have fixed it. I just told my TypeDescriptionProvider to expect an IObjectInstance rather than an ObjectInstance<T>. You should be able to drop your value converter.