DynamoDS / DynamoRevit

Dynamo Libraries for Revit
https://dynamobim.org
340 stars 188 forks source link

Request GetRevitSelection #1533

Open jhubers opened 7 years ago

jhubers commented 7 years ago

Dynamo version

1.2.1.3083

Revit version

2017

Operating system

Windows 10

What did you do?

Tried to make a Zero Touch node that outputs the selection of elements in Revit. Subscribed to the tab.PropertyChanged event of Revit as explained here: http://thebuildingcoder.typepad.com/blog/2015/03/element-selection-changed-event.html

What did you expect to see?

It works, but the node doesn't update.

What did you see instead?

Would be nice if Dynamo nodes could refresh by subscribing to a Revit event. Or if a new node could be made that shows the selected Revit elements and updates automatically when the selection changes.

ksobon commented 7 years ago

@jhubers you can do what you are asking for like this:

https://drive.google.com/file/d/0B3QQaPkepGSkcDlBeHNHSFJmTjQ/view

[NodeName("Current Selection"),
    NodeCategory(BuiltinNodeCategories.REVIT_SELECTION),
    NodeDescription("Current Revit Selection"),
    IsDesignScriptCompatible]
    public class CurrentSelection : SelectionChangedBase
    {
        public CurrentSelection()
        {
            InPorts.Add(new PortModel(PortType.Input, this, new PortData("AutoRefresh", Properties.Resources.PortDataFamilTypeToolTip)));
            OutPorts.Add(new PortModel(PortType.Output, this, new PortData("Elements", Properties.Resources.PortDataElementsToolTip)));
            RegisterAllPorts();
        }

        public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode> inputAstNodes)
        {
            var func = new Func<bool, IList<Revit.Elements.Element>>(ElementQueries.CurrentlySelected);
            var functionCall = AstFactory.BuildFunctionCall(func, inputAstNodes);
            return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), functionCall) };
        }
    }
public abstract class SelectionChangedBase : RevitNodeModel
    {
        private static bool _subscribed;
        protected SelectionChangedBase()
        {
            foreach (var tab in Autodesk.Windows.ComponentManager.Ribbon.Tabs)
            {
                if (tab.Id != "Modify") continue;
                if(!_subscribed) tab.PropertyChanged += PanelEvent;
                _subscribed = true;
            }

            ShouldDisplayPreviewCore = true;
        }

        private void PanelEvent(object sender, PropertyChangedEventArgs e)
        {
            OnNodeModified(true);
        }

        public override void Dispose()
        {
            base.Dispose();

            foreach (var tab in Autodesk.Windows.ComponentManager.Ribbon.Tabs)
            {
                if (tab.Id != "Modify") continue;
                if(_subscribed) tab.PropertyChanged -= PanelEvent;
                _subscribed = false;
            }
        }
    }

As you can see the trick is to use a NodeModel instead of a ZeroTouch. Only there you can use the OnNodeModified() method that forces it to refresh. So basically you subscribe to the tab.PropertyChanged event and when that triggers you force refresh the node.

This would have to be a custom node, and we can't really roll that into Dynamo since it uses AdWindows.dll That's not suported by Autodesk and may cause trouble but feel free to publish that as part of your package.

Cheers!

ksobon commented 7 years ago

cc: @kronz can we close this issue? Unless @mjkkirschner and @jnealb think its safe to use AdWindows.dll in DynamoRevit for this kind of functionality, I am afraid that we would just have to refuse this request.