PIAB and BindingSource

Topics: Policy Injection Application Block
Aug 10, 2008 at 8:40 PM

Hi,

 

to circumvent writing much code in all my DTO’s I just have them implement INotifyPropertyChanged by supplying the Event and an appropriate OnPropertyChanged method. I also created appropriate CallHandlers which intercept property changes and raise the appropriate events.

 

This works just fine in my unit-tests. But as soon as I try to bind a wrapped object in WinForms using a BindingSource.DataSource = myWrappedObject; I get an exception stating that the supplied object is not the same as the actual object (the one I wrapped).

 

Any ideas?

 

regards, Tilli

Aug 11, 2008 at 10:19 AM
Here's the Exception:
Test method PatientEditorTests.BindingTests.BindAgainstInterface threw exception:  System.ArgumentException: The value "[New Patient]" is not of type "xxx.Contract.Data.Patient" and cannot be used in this generic collection.
Parameter name: value.
System.ThrowHelper.ThrowWrongValueTypeArgumentException(Object value, Type targetType)
VerifyValueType(Object value)
System.Collections.IList.Add(Object value)
System.Windows.Forms.BindingSource.WrapObjectInBindingList(Object obj)
System.Windows.Forms.BindingSource.ResetList()
System.Windows.Forms.BindingSource.set_DataSource(Object value)
PatientEditorTests.BindingTests.BindAgainstInterface() in C:\xxx\MAIN\CLIENT\Modules\PatientEditorTests\BindingTests.cs: line 53

and here the simple code producing the error:

 

public void BindAgainstInterface() {
    var patient = new Patient();
    var wrappedPatient = PolicyInjection.Wrap<IPatient>(patient);
    var ctrl = new UserControl();
    var components = new System.ComponentModel.Container();
    
var bindingSource = new BindingSource(components) {DataSource = typeof (IPatient)};
    ctrl.DataBindings.Add(
new Binding("Text", bindingSource, "FullName", true));
    bindingSource.DataSource = wrappedPatient;
}

 

Aug 11, 2008 at 4:46 PM
Hi,

That's weird; why would the BindingSource's collection be instantiated as a list of Patient instead of IPatient? I suggest you debug the framework to find out about this (if you're using VS 2008).

Fernando
Aug 11, 2008 at 10:30 PM

Hi Fernando,

thanks! I was wondering that aswell. Even more so I am wondering how it can use generics to do so as it would have to emit code in order for that to work.

Aug 11, 2008 at 10:55 PM
Edited Aug 11, 2008 at 11:03 PM
Hi,

Did you happen to determine the cause for this behavior? You don't need to emit code to instantiate generic types; just make a closed version and instantiate it as with any other type. [update]
... which is exactly what the BindingSource does. It's still hard to see why this would happen from your isolated snippet, though. In any case, you need to make sure you initialize your BindingSource to the interface type (if possible).

Fernando
Aug 12, 2008 at 5:44 AM

Hi!

I added the URL manually in VS2008 but it did not download the symbols. The 2 buttons at the bottom stayed grayed-out. I did step through the PIAB code, though and found that first the BindingSource calls IRemotingTypeInfo.CanCastTo which returns false (is being checked if it’s a BindingManager or various types of lists), then the BS calls GetType() through the proxy which returns it’s REAL type (hence Patient, instead of IPatient).

Thanks for the tip on how to create generics not using emit. Didn’t know that J

Regards, Tilli

Aug 12, 2008 at 6:11 AM
I found a workaround!

If I bind against List<IPatient> { wrappedPatient } it works! Since BindingSource seems to wrap it into a list anyways, I'll just do that in my code then.

Thanks! Regards, Tilli
Aug 12, 2008 at 2:53 PM
True, the proxy returns the underlying proxy type. I didn't rembember it originally, but this has caused some problems in the past when type descriptors were involved (an unrelated issue with the same root cause).

Thanks for sharing your workaround.

Regards,
Fernando