views:

65

answers:

2

I'm currently completely baffled by the problem I'm having. I'm writing a plug-in for another application that provides a public .NET API. I've created a class named Room and I am using a PropertyGrid to allow users to see and edit the properties of the Room instances. A few properties are restricted to a set of standard values. Thus I am using custom TypeDescriptors with GetStandardValues() overrides to get the property grid to show a drop down for those properties.

This was all working just fine. I was getting drop downs, and I could edit values no problem. Yet now for some reason when I select an Room the PropertyGrid shows the properties with the type descriptors as a black box.

alt text

If I click on the box it turns white and I get a blinking cursor, yet I can't type anything. If I then select another Room my program crashes with the following exception:

System.InvalidCastException was caught
  Message=Unable to cast object of type 'DVAMC.Room' to type 'DVAMC.Room'.
  Source=DVAMC
  StackTrace:
       at DVAMC.BuildingTypeConverter.GetStandardValuesSupported(ITypeDescriptorContext context) in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\DVAMC Working\BuildingTypeConverter.cs:line 14
       at System.Windows.Forms.PropertyGridInternal.GridEntry.get_Flags()
       at System.Windows.Forms.PropertyGridInternal.GridEntry.get_NeedsDropDownButton()
       at System.Windows.Forms.PropertyGridInternal.PropertyDescriptorGridEntry.get_NeedsDropDownButton()
       at System.Windows.Forms.PropertyGridInternal.PropertyGridView.SelectRow(Int32 row)
       at System.Windows.Forms.PropertyGridInternal.PropertyGridView.SelectGridEntry(GridEntry gridEntry, Boolean fPageIn)
       at System.Windows.Forms.PropertyGridInternal.PropertyGridView.GridPositionData.Restore(PropertyGridView gridView)
       at System.Windows.Forms.PropertyGridInternal.PropertyGridView.Refresh(Boolean fullRefresh, Int32 rowStart, Int32 rowEnd)
       at System.Windows.Forms.PropertyGridInternal.PropertyGridView.Refresh()
       at System.Windows.Forms.PropertyGrid.Refresh(Boolean clearCached)
       at System.Windows.Forms.PropertyGrid.set_SelectedObjects(Object[] value)
       at System.Windows.Forms.PropertyGrid.set_SelectedObject(Object value)
       at DVAMC.RoomDetailsForm.set_RoomDetailsSelectedRoom(Room value) in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\DVAMC Working\RoomDetailsForm.cs:line 115
       at DVAMC.RoomDetailsForm.roomListTreeView_SelectionChanged(Object sender, EventArgs e) in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\DVAMC Working\RoomDetailsForm.cs:line 159
       at BrightIdeasSoftware.ObjectListView.OnSelectionChanged(EventArgs e)
       at BrightIdeasSoftware.ObjectListView.HandleApplicationIdle(Object sender, EventArgs e)
       at System.Windows.Forms.Application.ThreadContext.System.Windows.Forms.UnsafeNativeMethods.IMsoComponent.FDoIdle(Int32 grfidlef)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.RunDialog(Form form)
       at System.Windows.Forms.Form.ShowDialog(IWin32Window owner)
       at System.Windows.Forms.Form.ShowDialog()
       at DVAMC.RoomDetailsCmd.Execute(ExternalCommandData commandData, String& message, ElementSet elements) in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\DVAMC Working\RoomDetailsCmd.cs:line 44
  InnerException: 

The last item in the stack trace points to my BuildingTypeConverter.GetStandardValuesSupported() method which is shown below.

GetStandardValuesSupported(System.ComponentModel.ITypeDescriptorContext context)
{
    Room r = (Room)context.Instance; //this is line 14 referenced by the InvalidCastException's stack trace

    if (r.IsLinked)
    {
        return true;
    }
    else
    {
        return false;
    }
}

Now if I set a breakpoint at line 14 above and try to debug the debugger does not break at the breakpoint. In addition, if I add arbitrary code before the cast the stack trace from the InvalidCastException always seems to reference to first line of GetStandardValues() regardless of what it is. For example I tried the following.

public override bool GetStandardValuesSupported(System.ComponentModel.ITypeDescriptorContext context)
    {
        string s = "hello world";   //FIRST LINE
        int i = 0;


        Room r = (Room)context.Instance; 

        .....

I still got the same InvalidCastException. Yet it's stack trace reference the first line above where I initialize string s. In addtion, if I tried to set a breakpoint on this first line it was also not triggered.

Like I said before this was working just fine a day or so ago. I've even tried rolling back to previous revisions in my SVN repository. I've gone as far back as the first revision were I created the custom Type Descriptor class but still run into the problem with the InvalidCastExceptions. Does anyone have any idea what's going on?

A: 

It may be that the two types are actually different - for example if one of them is loaded from another version of some assembly than the other type. I'm not quite sure if this could happen in your case, but it could be a problem.

The easiest way to check this is to place breakpoint at the place where the exception is thrown. Then you can look at the two types in watches or immediate window and look at o1.GetType().Assembly. FullName (and similarly for the other object).

Tomas Petricek
A: 

If the stack trace always shows the same line even after you have changed the code that would indicate to me that the ProperyGrid is not running the same version of the assembly. This is further confirmed when you say you put a breakpoint but the breakpoint is never hit. If you are running inside of the debugger for Visual Studio I suggest that you look at the output window (Ctrl+W, O), which will list all of the assemblies (with their path) that are loaded in the run. I have seen assembly version confusion particularly when the assembly is in the GAC, where it insist upon loading an older version of the assembly.

Steve Ellinger
Yep, I have no idea why, but there was a separate copy of my DLL file in the root program folder. What's weird is my code seemd to be referencing both. For example I could catch a breakpoint in the SelectionChanged event handler, but after I set the PropertyGrid.SelectedObject property there it wouldn't catch a breakpoint in the GetStandardValues() method. I deleted the extra copy of the DLL and it worked perfectly again. Thanks!
Eric Anastas