We have a Grasshopper plugin that provides some extra components and we need some sort of global settings dictionary that is accessible from within our plugins namespace.
However, even with a simple int variable I cannot figure out how to implement this.
The aim is to be able to do
ELiSE.MyVar = 42;
or
int myVar = ELiSE.MyVar;
(where ELiSE is the namespace of our plugin) from anywhere within my plugin code, be it from components or widgets.
Where would I instantiate such a variable in order to make it accessible from everywhere? Iâve tried placing it in our AssemblyPriority method but it does not show up anywhere elseâŚ
As always, your help would be greatly appreciated!
Thanks and best regards,
Paul
Create a singleton class with static accessor. Then just normal fields.
namespace ELiSE {
public sealed class Settings {
private Settings() {} // private constructor, should only access through Instance. Any necessary initialization here, too.
Settings Instance => { get; } = new Settings(); // The gate into your settings.
public int MyVar { get; set; } = Int.MinValue; // initialize to min value of int. Can use any valid value here. Or init in the private constructor.
}
}
Cool @jesterking, the singleton approach seems to be a good one (although your code did not compile for me, something around Settings Instance => ... seems to be wrong.
I found this stackoverflow post on singletons and modified it a bit so it works like the Grasshopper.Instances.Whatever code.
namespace ELiSE
{
public class Instances
{
// Settings server instance.
private static SettingsServer _settingsServer;
// Room for other instaces, e.g. FooServer or BarServer
// Private constructor.
private Instances() { }
// Settings server accessor that allows only one instance.
public static SettingsServer SettingsServer
{
get
{
if (_settingsServer == null)
_settingsServer = new SettingsServer();
return _settingsServer;
}
}
}
public class SettingsServer
{
// Constructor
public SettingsServer(){}
}
}
Iâm not sure if Iâm bending the concept too much but it works
What jesterKing proposes does not allow you to change the values and keep them in another session of gh. If you need this, you can use grasshopper_kernel.xml to store your configuration using Grasshopper.Instances.Settings.GetValue()/SetValue() methods and use (although not necessary) the Settings class to easily access/edit them, for example (not tested):
public sealed class Settings {
private int myVar;
private Settings() {
//Load settings;
myVar = Grasshopper.Instances.Settings.GetValue("ELiSE.Settings.MyVar", int.MinValue);
}
Settings Instance => { get; } = new Settings(); // The gate into your settings.
public int MyVar {
get { return myVar; }
set {
if(myVar == value) return;
Grashopper.Instances.Settings.SetValue("ELiSE.Settings.MyVar", myVar);
myVar = value;
}
public int OtherVar{
get { return Grashopper.Instances.Settings.GetValue("ELiSE.Settings.OtherVar", 0); }
set { Grashopper.Instances.Settings.SetValue("ELiSE.Settings.OtherVar", value); }
}
}
It puts an ELiSE.xml file in the same folder as grasshopper_kernel.xml and you can always access the values inside that file by creating a new settings server with the correct name and accessing its values. Just be sure to always call WritePersistentSettings() whenever you make a change to the settings, because the server class doesnât update if the file changes.
Oh, nice, I didnât know that I could use the GH_SettingsServer class so easily⌠Thanks @Dani_Abalde and @DavidRutten!
I was planning to do my own settings class that writes a json to keep settings across sessions and also allows to write document specific settings to gh files using this approachâŚ
Thatâs also a nice one @fraguada, I wasnât aware of that.
However, this will not allow me to attach settings to individual grasshopper files I guess?
Is there âcommonâ provision to store settings within a grasshopper document?
I have two groups of settings, one that is global and different settings that are document specific.
No, you have to store data within your component during the Write() method. Technically you could cast the writer to a GH_Chunk and navigate towards the top of the hierarchy and append a new chunk there, but it sounds awfully risky. And youâd have to deal with potentially conflicting components, all trying to be the one true global standard.
Hereâs a way to store âglobalâ data in the *.gh file, but it is only available during Write() and Read() processes. Still, during runtime you can have your own data class running which associates with specific documents.
The component below will create a new chunk in the gh file and store some data in it: