Hi All,
I’ve followed the great little blog below to setup my first component on macos with VSCode for Rhino8 by by Steve Baer and Callum Sykes
While there are a few steps missing, like *.sln file and *.csproj generation, the big issue for me is how to include local png files as the component icons. Remember this is macos and VSCode.
Could someone provide some example csharp code for this, or maybe another blog post for a complete comopnent?
Glad you liked it. I need to review improvements to our templates that should make setup simpler.
This is really handy feedback. The .csproj will be generated by the dotnet command and the sln is created when vscode is opened / saved. I should add this to the guide.
Yes I’d agree. In Visual Studio windows creating resources and .resx’s is trivial. In VSCode I haven’t found an obvious interface for handling resources. Of course. It can be done manually which is my least favourite word in the english language.
C# code to get an embedded resource. It would be best to do this at start up, cache the icons and have the components look at your icon cache class to prevent unnecessary reloading.
var assembly = Assembly.GetExecutingAssembly();
var imageStream = assembly.GetManifestResourceStream("<assembly-name>.<icon-name>.png");
Bitmap bitmap = new Bitmap(imageStream);
return bitmap;
That was very good of you to be so prompt in trying to help me.
My apologies. Would you be so kind as to provide a full code example for a working csharp ‘hello world’ Grasshopper component that successfully loads the Icon while working on macos and VSCode?
I’m not quite achieving the desired result when trying to follow your comments, and ChatGPT hasn’t quite clarified where I’m going wrong.
This solution uses Embedded Resources. I prefer .resx’s as they give some nice statically typed resource names. But they’re not convenient to do without Visual Studio on windows. I’d bet Rider handles them nicely if you really need it on mac.
I have tried replicating your solution to embed the png files in the grasshopper component but I’m getting an error at runtime. It compiles but when loading Grasshopper I get the following error:
Exception has occurred: CLR/System.TypeInitializationException
An exception of type 'System.TypeInitializationException' occurred in Roofer_GH.gha but was not handled in user code: 'The type initializer for 'Roofer_GH.IconLoader' threw an exception.'
Inner exceptions found, see $exception in variables window for more details.
Innermost exception System.ArgumentNullException : Value can not be null Arg_ParamName_Name
at System.Drawing.Bitmap.InitializeFromStream(Stream stream)
at Roofer_GH.IconLoader.LoadIcon(String resourceName) in /Users/filipeb/10_DEV/GraphML_IO/Roofer_GH/IconLoader.cs:line 26
at Roofer_GH.IconLoader..cctor() in /Users/filipeb/10_DEV/GraphML_IO/Roofer_GH/IconLoader.cs:line 16
Another problem I’m having is that the *.sln file is not being generated as you mention. Could this be the issue?
For anyone arriving here with the same question the reference to the resource must include the namespace of your class, that is if you want to hardcode the access as in the example provided above.
Thank you all for your explanations, suggestions and code samples. It may be a silly question but what’s wrong with just doing
protected override System.Drawing.Bitmap Icon
{
get
{
return new System.Drawing.Bitmap("./path/to/file.png");
}
}
in the component.cs file?
I also just switched to VS code (from formerly Visual Studio) on Mac and there seems to no longer be the option (necessity? convenience? inconvenience?) of the Resources.resx file, and the auto-generated Designer.cs file…
Thank you @CallumSykes for the quick reply. So how would I go about not having all the image files hang around in the build folder? My plugin has some 70+ components, so hardcoding the path like in the example is not an option. I also tried what @Filipe_Brandao suggests here but no success yet. All my png files are (as before) in the folder PluginName/Properties/Resources/, but neither separated with dots nor with slashes as in a regular path worked.
I try to use the IconLoader class from @CallumSykes sample, changed the LoadIcon method to public and in the component class do return IconLoader.LoadIcon("file.png") then concatenate the rest of the path together in the method itself.
They’ll need to be considered as embedded resources somehow, that way they’re included in the dll. Using glob patterns should avoid having to hardcode them all.
Amazing, thank you so much!
The only thing I had to change was line 11 in IconLoader, because of a C# version incompatibility of ‘tafget-typed object creation’. Copilot suggested to change it to private static Dictionary<string, Bitmap> Cache { get; } = new Dictionary<string, Bitmap>();
And now it works like a charm