I have an interesting problem… I’m developing a Series of Grasshopper Components that utilize WPF windows to enter and store data. Everything works very well, but now I am also creating a Rhino Toolbar (with custom RhinoCommands) that also utilizes the same WPF forms. The funny bit is that I can use the forms in either the GH side or the Rhino side, but when I try to do both I get a URI resource error:
System.Exception: ‘The component ‘MyWindow’ does not have a resource identified by the URI ‘/MyAssembly;component/model/forms/mywindow.xaml’.’
Note: ‘MyAssembly’ holds both the GH component definitions and the xaml window definitions. A separate assembly is used for the custom RhinoCommands.
Even more curious is that once I open the window in the Rhino side, the GH side no longer works (throws URI resource error), but I can continue using it on the Rhino side. Does anyone know why this might be happening? Is it possible that once I use the WPF window in Rhino during a session, it modifies the URI path (or just can’t find it anymore)?
Any insight would be greatly appreciated.
This smells like a DLL conflict to me. Probably your Rhino plugin and your GH plugin are using two different versions of a certain dll. Whichever one goes “looking” for the DLL first will load it into the AppDomain, and then the other one will be forced to use the other loaded. This may be the
MyAssembly dll or it might be one of its dependencies.
Thanks Andrew! I’ll investigate the AppDomain… I should probably break out the WPF forms into their own project/DLL to prevent conflicts
I usually test “which one is loaded?” in the debugger by doing:
typeof(SOME_TYPE_DEFINED_IN_MY_ASSEMBLY).Assembly.Location — you can see which DLL got loaded.
@anthoniekramer not sure if you solved this or not…if so please ignore.
I have two thoughts that hit us sometimes with WPF. The first one is how you are referencing the resource, I’ve found it much more reliable to use pack reference uris rather than relative paths to a xaml resource.
The other thing we hit sometimes, is using 1 resource in your application in multiple placed without adding the x:Shared=“false” attribute to an item that is referenced in multiple places. This is especially helpful for Images / Canvases that are used by multiple controls. Without this attribute the resource will render in one spot, but be missing in all others.
It looks like I’ve solved it, but as a WPF novice I’m not entirely sure why…
The WPF forms that I created inside of my GrasshopperComponent project did not work in other dlls. I think this is because my project was defined as a Class Library, not a WPF User Control Library.
I created a new project that was a WPF User Control Library (Framework 4.7.2) and refactored my solution by extracting out all of the WPF stuff (xaml, etc.) and putting it into the new WPF User Control Library Project. This allowed me to use the WPF forms in both my Grasshopper project, and my Rhino Plugin project without the resource issue.
The main difference between the two projects from what I can tell is the addition of the ‘ProjectTypeGuids’ which specifies the project as a WPF User Control Library:
This pointed me in the right direction, but I’m still not clear if/why the class library type that the Grasshopper Components are built on are the limitation:
Thanks everyone for showing me the way!
I think I’ve figured it out, see below. I don’t have a deep understanding of why, but it is probably related to how Windows allows Uris to be shared between dlls. In my case, I think it was based on the project / assembly type that my forms were using.
Yeah we extract all of our wpf UI into libraries like that to share across projects. Works great! Glad you got it sorted.
Yes getting a path relative to the executing application is a bit tricky in .Net. There are a couple of ways to get this information and the result is not always the same. Especially if your app plugs into another app, which plugs into in another app.
In general using an usercontrol library is the way you should go. This just makes sense on all levels. The Grasshopper component library should only interface to Grasshopper and act as an Adapter. This project structure allows you to build a wpf test app (with mocking your model function) without the need to run Rhino/GH just to test your views.
In general Anthonys hint to use the pack: notation to reference resources is another thing you should consider. It usually will solve these issues for what I mentioned in the beginning