Are you developing a plug-in that runs a command with a dialog in interactive mode, and the command line in scripted mode? Then this new feature is for you: command line property attributes, especially if you are already using the MVVM (Model / View / ViewModel) architecture.
What are command line property attributes?
Rhino BETA has a new set of property attributes in the Rhino.UI library that you can use to decorate properties on the viewmodel. Using a so-called CommandLineView (also available in the Rhino.UI library), the commandline will be built automatically from the information in the attributes, and you do not need to keep the code for interactive and scripted mode in sync.
Below is an example of the [RhinoInteger] attribute. It comes from the example project (see below) and contains instructions on how to build the command line for this option: where to put it (1), what the prompt should be when the user wants to change it, and a minimum value (a maximum can be provided as well).
[RhinoInteger(1, Prompt = "Give a new Id", MinValue = 1)]
public int Id
{
get => Model.Id;
set
{
Model.Id = value;
RaisePropertyChanged(nameof(Id));
}
}
Why would you want to use this?
If you have more than one or two properties that the user can change, you may find yourself making a view model for a dialog, and a completely separate code path for scripted mode. With the command line property attributes this is no longer needed. Once you have the Model and ViewModel, you can use the ViewModel for a dialog view in interactive mode and the CommandLineView that comes in the Rhino.UI library for scripted mode. The dialog and the CommandLineView play the role of the View in the MVVM architecture: they allow the user to interact with the business logic.
Supporting a dialog and a commandline is then as easy as:
MyModel model = GetModel(); // from file, database, command settings, ...
MyViewModel vm = new(model); // the model is the data storage layer of the view model
Result res;
if (mode == RunMode.Interactive)
{
MyDialog dialog = new(vm);
res = dialog.ShowSemiModel(); // show a dialog for the view model
}
else
{
CommandLineView clv = new(vm);
GetOption go = new();
go.SetCommandPrompt("Command options");
res = clv.Run(go); // build a commandline for the viewmodel
}
if (res != Result.Success)
return res;
// After the dialog is closed or the command line GetOption has completed
// do something with the result from the view model. The Result property is
// just an example; it could be anything.
GeometryBase commandResult = vm.Result;
doc.Objects.Add(commandResult);
return res;
A complete example can be found in the samples repository:
Feature summary
-
Decorate view model properties with a 1-line attribute that contains information on how to build the command line for that option
- use custom names that do not match the property name
- provide a prompt
- names and prompts can be localized
- minimum and maximum values for number options
-
Attributes
[RhinoToggle]set a boolean value[RhinoInteger]and[RhinoNumber]to set integer and floating point numbers[RhinoEnum]let the user choose from a list ofenumvalues[RhinoString]lets the user set a string[RhinoStringList]lets the user choose from a list of strings[RhinoChild]lets you use nested options[RhinoAction]lets you run an action: select geometry in the document for example, or reset values to defaults.
-
keep code for dialog and commandline in sync
- no need to maintain a separate code path for scripted mode building the commandline by hand.
- add a property to the view model, decorate it with an attribute and it will appear on the command line
Questions and Suggestions
We are using this approach in some of the C# commands that are part of Rhino, and we find it very useful. We’d like to hear what you think, how you use it, what’s not working for you and what you’d like to see added and improved.