I will actually argue to the contrary. It’s not that bad. I usually use Grasshopper for the comparison, and in this particular case the Dynamo methods for defining dropdowns are pretty decent. Here’s one of them adopted from Max’s recent contributions to DynamoRevit repo:
[NodeName("Select Rule Type")]
[NodeCategory("Revit.Filter.RuleType")]
[NodeDescription("FilterTypeSelectorDescription", typeof(DSRevitNodesUI.Properties.Resources))]
[IsDesignScriptCompatible]
public class RuleTypes : CustomGenericEnumerationDropDown
{
public RuleTypes() : base("RuleType", typeof(Revit.Filter.FilterRule.RuleType)) { }
}
This inherits from this class:
/// <summary>
/// Generic UI Dropdown node baseclass for Enumerations.
/// This class populates a dropdown with all enumeration values of the specified type.
/// </summary>
public abstract class CustomGenericEnumerationDropDown : RevitDropDownBase
{
/// <summary>
/// Generic Enumeration Dropdown
/// </summary>
/// <param name="name">Node Name</param>
/// <param name="enumerationType">Type of Enumeration to Display</param>
public CustomGenericEnumerationDropDown(string name, Type enumerationType) : base(name) { this.EnumerationType = enumerationType; PopulateDropDownItems(); }
/// <summary>
/// Type of Enumeration
/// </summary>
private Type EnumerationType
{
get;
set;
}
protected override CoreNodeModels.DSDropDownBase.SelectionState PopulateItemsCore(string currentSelection)
{
PopulateDropDownItems();
return SelectionState.Done;
}
/// <summary>
/// Populate Items in Dropdown menu
/// </summary>
public void PopulateDropDownItems()
{
if (this.EnumerationType != null)
{
// Clear the dropdown list
Items.Clear();
// Get all enumeration names and add them to the dropdown menu
foreach (string name in Enum.GetNames(EnumerationType))
{
Items.Add(new CoreNodeModels.DynamoDropDownItem(name, Enum.Parse(EnumerationType, name)));
}
Items = Items.OrderBy(x => x.Name).ToObservableCollection();
}
}
/// <summary>
/// Assign the selected Enumeration value to the output
/// </summary>
public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode> inputAstNodes)
{
// If the dropdown is still empty try to populate it again
if (Items.Count == 0 || Items.Count == -1)
{
if (this.EnumerationType != null && Enum.GetNames(this.EnumerationType).Length > 0)
{
PopulateItems();
}
}
// get the selected items name
var stringNode = AstFactory.BuildStringNode((string)Items[SelectedIndex].Name);
// assign the selected name to an actual enumeration value
var assign = AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), stringNode);
// return the enumeration value
return new List<AssociativeNode> { assign };
}
}
If you have pasted the CustomGenericEnumerationDropDown
into your code, then you can use that first method to define dropdowns by simply inheriting from it.
Cheers!
PS. @Thomas_Mahon it is correct that you can go all out custom WPF dropdown, and use a NodeModel
route, but then yes, one would need to create all of the interaction logic, handle events, etc. It does get a little more cumbersome then. For this application its not necessary.