I need of help to properly configure Rhino.Inside for a demonstration WPF desktop app. After having updated Rhino to the latest Version 8.20.25154.13001. I added the Rhino.Inside library to the project Dependencies list.
When using this Rhino.Inside Version 8.0.7-beta, the referenced Grasshopper and RhinoCommon Versions are 8.0.23304.9001. There is warning that the Grasshopper.dll is .NETFramework V4.8.1. Because I do not intend to use Grasshopper in this test app, I have not included a PackageReference for Grasshopper in the project file csprog file as follows:
The RhinoCommon.dll version, as of the latest update is 8.20.25154.13001. It would appear that Rhino.Inside is looking for an older version of RhinoCommon, thus the exception.
As an attempted workaround, I added RhinoCommon Nuget package Version 8.20.25447.11001-rc, (the latest Nuget available), which in turn modified the Rhino.Inside dependency to:
This produces a warning “Detected package version outside of dependency constraint: Grasshopper 8.0.23304.9001 requires RhinoCommon (= 8.0.23304.9001) but version RhinoCommon 8.20.25147.11001-rc was resolved.”
After a clean and rebuild, running the app produces the following exception:
I used FileExplorer to see the Version number of RhinoCommon in C:\Program Files\Rhino 8\System and it is the same as the version of the last Rhino update - Version 8.20.25154.13001.
So current my questions are:
Is there an issue with the versioning of Rhino.Inside at 8.0.7-beta that looks for RhinoCommon and Grasshopper version 8.0.23304.9001?
In VS2022, does installing the Nuget RhinoCommon to a more recent version create a false positive in Rhino.Inside, that is, though the Runtime Exception indicates looking at the Nuget version of RhinoCommon, does an underlying issue still exists? Namely, Rhino.Inside must look for the exact version of the RhinoCommon.dll version in C:\Program Files\Rhino 8\System. And if the exact version is not found, a System.IO.FileNotFoundException is triggered?
And last, is there a solution that I am missing, perhaps in the csprog file?
Or, is best to wait until all versions, (Rhino.Inside, Nuget RhinoCommon, and App RhinoCommon) to have exact alignment?
Thanks.
Is there an issue with the versioning of Rhino.Inside at 8.0.7-beta that looks for RhinoCommon and Grasshopper version 8.0.23304.9001?
No. The warning regarding .NET 4.8 is okay. Currently NuGet packages for RhinoCommon and Grasshopper do not have netcore builds.
In VS2022, does installing the Nuget RhinoCommon to a more recent version create a false positive in Rhino.Inside, that is, though the Runtime Exception indicates looking at the Nuget version of RhinoCommon, does an underlying issue still exists? Namely, Rhino.Inside must look for the exact version of the RhinoCommon.dll version in C:\Program Files\Rhino 8\System. And if the exact version is not found, a System.IO.FileNotFoundException is triggered?
And last, is there a solution that I am missing, perhaps in the csprog file?
Or, is best to wait until all versions, (Rhino.Inside, Nuget RhinoCommon, and App RhinoCommon) to have exact alignment?
Thanks.
Rhino.Inside v8 references v8.0.* versions of RhinoCommon and Grasshopper assemblies since that’s what the original Rhino 8 was released on. Any Rhino 8 newer than the original release has a larger version number and satisfies the requirement. The NuGet assemblies are not strong-named so the link is flexible.
From what I gathered in your comments above seems like the solution is working and you only get an error loading RhinoCommon when trying to debug? When launching a dotnet app that is trying to load Rhino, it needs to find and resolve RhinoCommon to the one that is shipped with Rhino. So it is best not to add any other RhinoCommon references to your project.
It would be great if you can send a simpler iteration of your solution that replicates the problem so I can run on my machine and see what the problem is.
Hi, Ehsan:
I removed the reference to RhinoCommon in the Project Dependencies, but still get the original runtime exception where for RhinoCommon “could not load file or assembly”. I have attached a .zip file of the app source for your review and comments. Test_WPF_RhinoInside.zip (652.9 KB)
The MainWindow.xaml does not have a WindowsFormHost statement to render a Rhino Viewport, but perhaps it should. In this initial test, I wanted to duplicate the look seen in YouTube video.
Rhino and later Grasshopper appear to be free floating over the top of Revit.
Looking ahead, I would like that the Rhino app to be embedded in a WPF UserControl rendered in MainWindow.xaml. I don’t want just a Viewport, rather the full application with specific toolbars.
Currently, I have a Rhino Plugin where the WPF MainWindow hovers over Rhino, but I hope with Rhino.Inside, the UI will become a single interface.
I am now using WindowsFormsHost in the MainWindow.xaml to render the Rhino.Inside Viewport. Though the program compiles, I get the same original runtime exception as before. The zip file related to the picture is WPF_RhinoInside_Embedded.zip (694.6 KB)
Thanks, Dave
Hi David. Sorry for the late reply. Two things to note here:
The App instance must be created before loading RhinoCore. Then rhino uses this app instance.
RhinoCommon is accessed before Rhino is loaded. Let me explain this one below.
When is RhinoCommon available?
You project that is using Rhino.Inside allows you to use RhinoCommon API since that is a transitive dependency. However Rhino.Inside does not bring RhinoCommon into your project build folder. So the one that is shipped with Rhino must be loaded. However Rhino assembly resolver needs to be set up before so this library can be found.
So the code below normally does not work because to run the Main function, dotnet needs to resolve the assemblies and find the types that are used inside this code, in this case types referencing RhinoCommon API. So this fails:
static void Main(string[] args)
{
RhinoInside.Resolver.Initialize();
using (new RhinoCore(new string[] { "/NOSPLASH" }, Rhino.Runtime.InProcess.WindowStyle.Hidden))
{
}
}
I modified the code to put the parts that access RhinoCommon in a separate static class. This defers loading RhinoCommon until after the RhinoInside.Resolver.Initialize(); call is complete and Rhino resolver can find its assemblies. Then the Init.LoadRhino(); call can be completed correctly since dotnet can now find RhinoCommon.
This modified code also initialized the App instance correctly before loading Rhino.
internal class Program
{
[STAThread]
static void Main(string[] args)
{
try
{
// Initialize Rhino.Inside before starting the WPF application
RhinoInside.Resolver.Initialize();
Init.LoadRhino();
}
catch (Exception ex)
{
MessageBox.Show($"Failed to initialize Rhino.Inside: {ex.Message}",
"Initialization Error",
MessageBoxButton.OK,
MessageBoxImage.Error);
}
}
}
static class Init
{
public static void LoadRhino()
{
// Create WPF application (Rhino then uses this already existing app instance)
var app = new App();
app.InitializeComponent();
// Start Rhino core (headless mode)
using (new RhinoCore(new string[] { "/NOSPLASH" }, Rhino.Runtime.InProcess.WindowStyle.Hidden))
{
app.Run();
}
}
}
Hi, Ehsan:
Thank you for your research. Based on your reply, I will be testing this revised configuration and then post my results.
Many years ago I started with development of C# Grasshopper Components, then added WPF windows to Grasshopper, and most recently, moved to developing a WPF based Plugin for Rhino.
I recently have considered Rhino.Inside as an alternative to a Rhino Plugin. It seems a cleaner approach. My understanding is that, if a Rhino Viewport is embedded, or rendered, in a WinFormsHost, in WPF, the full Rhino functionality is not available, just a ViewPort. A user interface must be developed and all display functionality must be driven through the DisplayConduit.
The preferred configuration is to use Rhino.Inside much like Rhino.Inside.Revit, where the full Rhino and Grasshopper are available and free floating. This reduces my programming requirements significantly, yet gives me the full power of the Rhino GUI. I can ‘fix’ Rhino to a screen position by unchecking the Main Window Title Bar and then allow Grasshopper to be free floating, even in a second monitor.
This is a screen grab of my Rhino Plugin, with the Plugin being a child of Rhino. My hope is to have the same visual configuration, but Rhino as a child of my “Rhino.Inside” App. I hope my understanding is correct.
… On to testing Rhino.Inside with a minimum App.
Thanks again, Dave
Hi, Ehsan:
Try as I might, with the code pattern you provided, though the program compiles, I still get a hard crash at “using (new RhinoCore(new string { “/NOSPLASH” }, WindowStyle.Hidden))”. Attached are the files I am testing. WPF_Rhino..Inside_Test2.zip (5.3 KB)
You changed stuff a bit outside of what I suggested. Here are the fixes:
The whole point of resolver is to resolve dotnet and native assemblies from Rhino system folder. This does not seem necessary. Let me know that does NOT work.
Hi, Ehsan:
I have remove all the extra code from the Program.cs file as well as removing an attempt to open a new Template.3DM file in MainWindow.Xaml.cs. I had to include Nuget Rhino.Inside and RhinoCommon libraries for the program to compile. After clean and rebuilt, the VC10 app opens with no problem.
I see the Zoo has checked for my Rhino license. But, no Rhino.Inside window displays. I looked in the Task Manager and see that Rhino.Inside is attached.
Hi, Eshan:
Got it! Changing the WindowStyle to Normal shows the Rhino.Inside window, ie,
// Start Rhino core and then run the WPF application.
// The 'using' block ensures RhinoCore is disposed of when the app closes.
using (new RhinoCore(new string[] { "/NOSPLASH" }, Rhino.Runtime.InProcess.WindowStyle.**Normal**))
{
app.Run();
}
}