I'm struggling with monitoring Revit for element selection changes.
Window selections are no problem; monitoring element selection changes as a user "Control Picks" them is the main issue im working on a solution for. Way back Revit apparently had a "Element Selection Changed" Method but its been hidden/deprecated to the dismay of many in our community.
Because of this many in our community have come up with some great ideas to solve this seemingly rudimentary issue.
Specifically, detailed on Jeremy Tammicks awesome site The Building Coder, is this post which lays out the three most viable workarounds.
The one ive tried to implement is #3 which was originally suggested by a member of our community named Vilo here. Jeremy Tammick has made this code available for our use in the SDK Samples. Here is the repository of the current "working state" of my implementation.
Jeremy had great suggestions as usual but the issues below remain.
If you've found a solution to the main problem of "Element Selection Changed Monitoring" or to the implementation of Vilo's suggestion to subscribe to the Modify Tabs property changed event i, and i suspect many other, would appreciate some feedback.
Solved! Go to Solution.
I'm struggling with monitoring Revit for element selection changes.
Window selections are no problem; monitoring element selection changes as a user "Control Picks" them is the main issue im working on a solution for. Way back Revit apparently had a "Element Selection Changed" Method but its been hidden/deprecated to the dismay of many in our community.
Because of this many in our community have come up with some great ideas to solve this seemingly rudimentary issue.
Specifically, detailed on Jeremy Tammicks awesome site The Building Coder, is this post which lays out the three most viable workarounds.
The one ive tried to implement is #3 which was originally suggested by a member of our community named Vilo here. Jeremy Tammick has made this code available for our use in the SDK Samples. Here is the repository of the current "working state" of my implementation.
Jeremy had great suggestions as usual but the issues below remain.
If you've found a solution to the main problem of "Element Selection Changed Monitoring" or to the implementation of Vilo's suggestion to subscribe to the Modify Tabs property changed event i, and i suspect many other, would appreciate some feedback.
Solved! Go to Solution.
Solved by FAIR59. Go to Solution.
PropertyChanged event unsubscribing works only for public static methods
public static void TabPropertyChangedEvent(object sender, PropertyChangedEventArgs e)
{
PropertyChanged event unsubscribing works only for public static methods
public static void TabPropertyChangedEvent(object sender, PropertyChangedEventArgs e)
{
there is a 4th workaround.
Every time the selection changes, a button has the option to check if it should be enabled via the AvailabilityClassName property. The downside of this mechanisme is, that the button needs to visible. This can easily be accomplished by adding the button to the QuickAccessToolBar.
Define the button in the OnStartup method
public Autodesk.Revit.UI.Result OnStartup(UIControlledApplication application) { application.CreateRibbonTab("FAIR"); RibbonPanel m_ribbonPanel = application.CreateRibbonPanel("FAIR", "ModifyPanel"); string thisAssemblyPath = Assembly.GetExecutingAssembly().Location; PushButtonData buttonData = new PushButtonData("cmd_Dummy", string.Format("X"), thisAssemblyPath, "FAIR_Space.cmd_Dummy"); buttonData.AvailabilityClassName = "FAIR_Space.CommandEnabler"; m_ribbonPanel.AddItem(buttonData); application.ControlledApplication.ApplicationInitialized+=ControlledApplication_ApplicationInitialized; return Result.Succeeded; }
with the CommandExecute-method and AvailabilityClass
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] public class cmd_Dummy : IExternalCommand { public Autodesk.Revit.UI.Result Execute(ExternalCommandData revit, ref string message, ElementSet elements) { return Result.Succeeded; } } public class CommandEnabler : IExternalCommandAvailability { public bool IsCommandAvailable(UIApplication uiApp, CategorySet catSet) { UIDocument uidoc = uiApp.ActiveUIDocument; if (uidoc == null) return false; Autodesk.Revit.UI.Selection.Selection sel = uidoc.Selection; // Raise the SelectionChangedEvent return false; // disable button } }
In the ControlledApplication_ApplicationInitialized-method move the button to the QuickAccessToolBar.
void ControlledApplication_ApplicationInitialized(object sender, Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs e) { adWin.RibbonControl ribbon = adWin.ComponentManager.Ribbon; adWin.RibbonTab FAIRTab = null; adWin.RibbonPanel MyPanel = null; adWin.RibbonItem MyButton = null; // find MyPanel and MyButton foreach (var tab in ribbon.Tabs) { if (tab.Id == "FAIR") { FAIRTab = tab; foreach (var panel in tab.Panels) { if (panel.Source.Title == "ModifyPanel") { MyPanel = panel; foreach (var item in panel.Source.Items) { if (item.Id == "CustomCtrl_%CustomCtrl_%FAIR%ModifyPanel%cmd_Dummy") { MyButton = item; break; } } } } break; } } if (MyPanel != null && MyButton != null && FAIRTab != null ) { // find a "nice"position for the button int position = 0; foreach (var item in adWin.ComponentManager.QuickAccessToolBar.Items) { if (string.IsNullOrWhiteSpace(item.Id)) continue; position++; if (item.Id == "ID_REVIT_FILE_PRINT") break; } // place button on QuickAccessToolBar if (position < adWin.ComponentManager.QuickAccessToolBar.Items.Count) { adWin.ComponentManager.QuickAccessToolBar.InsertStandardItem(position, MyButton); } else adWin.ComponentManager.QuickAccessToolBar.AddStandardItem(MyButton); // remove button from MyPanel and hide tab if no panels FAIRTab.Panels.Remove(MyPanel); if (FAIRTab.Panels.Count == 0) FAIRTab.IsVisible = false; } }
there is a 4th workaround.
Every time the selection changes, a button has the option to check if it should be enabled via the AvailabilityClassName property. The downside of this mechanisme is, that the button needs to visible. This can easily be accomplished by adding the button to the QuickAccessToolBar.
Define the button in the OnStartup method
public Autodesk.Revit.UI.Result OnStartup(UIControlledApplication application) { application.CreateRibbonTab("FAIR"); RibbonPanel m_ribbonPanel = application.CreateRibbonPanel("FAIR", "ModifyPanel"); string thisAssemblyPath = Assembly.GetExecutingAssembly().Location; PushButtonData buttonData = new PushButtonData("cmd_Dummy", string.Format("X"), thisAssemblyPath, "FAIR_Space.cmd_Dummy"); buttonData.AvailabilityClassName = "FAIR_Space.CommandEnabler"; m_ribbonPanel.AddItem(buttonData); application.ControlledApplication.ApplicationInitialized+=ControlledApplication_ApplicationInitialized; return Result.Succeeded; }
with the CommandExecute-method and AvailabilityClass
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] public class cmd_Dummy : IExternalCommand { public Autodesk.Revit.UI.Result Execute(ExternalCommandData revit, ref string message, ElementSet elements) { return Result.Succeeded; } } public class CommandEnabler : IExternalCommandAvailability { public bool IsCommandAvailable(UIApplication uiApp, CategorySet catSet) { UIDocument uidoc = uiApp.ActiveUIDocument; if (uidoc == null) return false; Autodesk.Revit.UI.Selection.Selection sel = uidoc.Selection; // Raise the SelectionChangedEvent return false; // disable button } }
In the ControlledApplication_ApplicationInitialized-method move the button to the QuickAccessToolBar.
void ControlledApplication_ApplicationInitialized(object sender, Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs e) { adWin.RibbonControl ribbon = adWin.ComponentManager.Ribbon; adWin.RibbonTab FAIRTab = null; adWin.RibbonPanel MyPanel = null; adWin.RibbonItem MyButton = null; // find MyPanel and MyButton foreach (var tab in ribbon.Tabs) { if (tab.Id == "FAIR") { FAIRTab = tab; foreach (var panel in tab.Panels) { if (panel.Source.Title == "ModifyPanel") { MyPanel = panel; foreach (var item in panel.Source.Items) { if (item.Id == "CustomCtrl_%CustomCtrl_%FAIR%ModifyPanel%cmd_Dummy") { MyButton = item; break; } } } } break; } } if (MyPanel != null && MyButton != null && FAIRTab != null ) { // find a "nice"position for the button int position = 0; foreach (var item in adWin.ComponentManager.QuickAccessToolBar.Items) { if (string.IsNullOrWhiteSpace(item.Id)) continue; position++; if (item.Id == "ID_REVIT_FILE_PRINT") break; } // place button on QuickAccessToolBar if (position < adWin.ComponentManager.QuickAccessToolBar.Items.Count) { adWin.ComponentManager.QuickAccessToolBar.InsertStandardItem(position, MyButton); } else adWin.ComponentManager.QuickAccessToolBar.AddStandardItem(MyButton); // remove button from MyPanel and hide tab if no panels FAIRTab.Panels.Remove(MyPanel); if (FAIRTab.Panels.Count == 0) FAIRTab.IsVisible = false; } }
Wow! I wish I could allot more than one like for this. It deserves dozens, at least.
Wow! I wish I could allot more than one like for this. It deserves dozens, at least.
Thank you for the input Gopinath! Illuminating! I will make adjustments and see if this solves one of the problems im having.
Best wishes,
Chris
Thank you for the input Gopinath! Illuminating! I will make adjustments and see if this solves one of the problems im having.
Best wishes,
Chris
Frank, firstly I share Jeremy's sentiment! Your suggestion appears to not only mitigate the open issues I'm having but, more than that, it eliminates the need for an event entirely! Woohoo! Ill be implementing this as soon as i can and will report back.
Many thanks from Portland, Oregon
Chris
Frank, firstly I share Jeremy's sentiment! Your suggestion appears to not only mitigate the open issues I'm having but, more than that, it eliminates the need for an event entirely! Woohoo! Ill be implementing this as soon as i can and will report back.
Many thanks from Portland, Oregon
Chris
Correction to my last post. "...eliminates the nedd for a time or property watcher entire.'
Correction to my last post. "...eliminates the nedd for a time or property watcher entire.'
Elapsed times to report a count of selected elements for the three most viable workarounds are very close and, to me, completely acceptable.
Though the simplest and most dependable is definitely FAIR59's contribution.
Otherwise i'd go with the OnIdling approach.
Thanks again Frank!
-------------------------------------------------------------------------- Selection Monitor - OnPropertyChanged Element Id's: <hidden> Count: 600 Elapsed Time: 0.0041 seconds --------------------------------------------------------------------------
-------------------------------------------------------------------------- Selection Monitor - OnIdling Element Id's: <hidden> Count: 600 Elapsed Time: 0.0033 seconds --------------------------------------------------------------------------
-------------------------------------------------------------------------- Selection Monitor - Fair Availability Class Name Workaround Element Id's: <hidden> Count: 600 Elapsed Time: 0.0048 seconds --------------------------------------------------------------------------
Elapsed times to report a count of selected elements for the three most viable workarounds are very close and, to me, completely acceptable.
Though the simplest and most dependable is definitely FAIR59's contribution.
Otherwise i'd go with the OnIdling approach.
Thanks again Frank!
-------------------------------------------------------------------------- Selection Monitor - OnPropertyChanged Element Id's: <hidden> Count: 600 Elapsed Time: 0.0041 seconds --------------------------------------------------------------------------
-------------------------------------------------------------------------- Selection Monitor - OnIdling Element Id's: <hidden> Count: 600 Elapsed Time: 0.0033 seconds --------------------------------------------------------------------------
-------------------------------------------------------------------------- Selection Monitor - Fair Availability Class Name Workaround Element Id's: <hidden> Count: 600 Elapsed Time: 0.0048 seconds --------------------------------------------------------------------------
Thank you very much for testing and benchmarking and reporting the interesting results.
Could you share the add-in that you use to generate those?
I think this could potentially make a very illuminating and instructive blog post.
Thank you very much for testing and benchmarking and reporting the interesting results.
Could you share the add-in that you use to generate those?
I think this could potentially make a very illuminating and instructive blog post.
Absolutely Jeremy. Ill post a link first thing in the morning (Portland Oregon USA time TUesday 1/14/2020 @ approx 9:00am).
Absolutely Jeremy. Ill post a link first thing in the morning (Portland Oregon USA time TUesday 1/14/2020 @ approx 9:00am).
Jeremy, attached is a zip file of the solution containing three of the four workarounds for selection monitoring. The solution should open and compile right into the "C:\ProgramData\Autodesk\Revit\Addins\2020" directory.
Jeremy, attached is a zip file of the solution containing three of the four workarounds for selection monitoring. The solution should open and compile right into the "C:\ProgramData\Autodesk\Revit\Addins\2020" directory.
I am currently using workaround 1. OnIdling event ot the three, now four, identified so far, and am having a few issues and from the forums there is clearly a degree of unreliability with this approach and after all they are all workarounds. As others have said, wanting to know the current element selection is a common requirement for developers and 'a seemingly rudimentary issue'. If this is the case why do Autodesk and the Revit/Api/Sdk developpers make it so hard and why did they abandon the ElementSelectionChanged method. So many developers reinventing the wheel and each spending hours trying to figure which is the least worst workaround for something that should be really simple along with the vague threat that if we come up with something too good or clever it might well be illegal ! It would really be helpful to understand a bit what their strategy and logic is or after all these years are they just too busy to implement a solution for this and enjoy watching us all battle with it ! Alternatively do they not want us to do this so make it really hard if so why not just tell us that or block it completely. Workaround 4 looks quite promising and interesting so I think I will go and spend a few hours on that now but really we shouldn't have to experiment like this.
I am currently using workaround 1. OnIdling event ot the three, now four, identified so far, and am having a few issues and from the forums there is clearly a degree of unreliability with this approach and after all they are all workarounds. As others have said, wanting to know the current element selection is a common requirement for developers and 'a seemingly rudimentary issue'. If this is the case why do Autodesk and the Revit/Api/Sdk developpers make it so hard and why did they abandon the ElementSelectionChanged method. So many developers reinventing the wheel and each spending hours trying to figure which is the least worst workaround for something that should be really simple along with the vague threat that if we come up with something too good or clever it might well be illegal ! It would really be helpful to understand a bit what their strategy and logic is or after all these years are they just too busy to implement a solution for this and enjoy watching us all battle with it ! Alternatively do they not want us to do this so make it really hard if so why not just tell us that or block it completely. Workaround 4 looks quite promising and interesting so I think I will go and spend a few hours on that now but really we shouldn't have to experiment like this.
This is a really nice and elegant solution. I am trying to implement this with a modeless window that will respond to user selection changes and it seems that I will have to have a singleton class that has the CommandEnabler logic to somehow then get to my view (window) and ViewModel (as the window.DataContext) in order to actually use the current selection information that is gathered. Just wondering if you have taken this next step in some way that you are willing to discuss.
This is a really nice and elegant solution. I am trying to implement this with a modeless window that will respond to user selection changes and it seems that I will have to have a singleton class that has the CommandEnabler logic to somehow then get to my view (window) and ViewModel (as the window.DataContext) in order to actually use the current selection information that is gathered. Just wondering if you have taken this next step in some way that you are willing to discuss.
Can you test this selection monitor add-in also with your add-in ?
http://use-full.com/RevitAddin1.zip
how does is work,
If the left mousebutton is clicked, or the esc is pressed, there is an event fired.
Because the mousebutton / escape fired before the selection is recognized these events start the idle event handler.
After the idle event is fired the selection is displayed in the userform and the idle handler is removed.
kind regards,
Ivo Lafeber
Can you test this selection monitor add-in also with your add-in ?
http://use-full.com/RevitAddin1.zip
how does is work,
If the left mousebutton is clicked, or the esc is pressed, there is an event fired.
Because the mousebutton / escape fired before the selection is recognized these events start the idle event handler.
After the idle event is fired the selection is displayed in the userform and the idle handler is removed.
kind regards,
Ivo Lafeber
@FAIR59 This is awesome.
In my experience this workaround works a lot better than using the Modify tab for the following reasons :
@FAIR59 This is awesome.
In my experience this workaround works a lot better than using the Modify tab for the following reasons :
Which Using Assembly is adWin or RibbonTab, just can't find it?
Thx
Which Using Assembly is adWin or RibbonTab, just can't find it?
Thx
Its this one Josef "C:\Program Files\Autodesk\Revit 2021\AdWindows.dll"
Change the year for your needs.
Its this one Josef "C:\Program Files\Autodesk\Revit 2021\AdWindows.dll"
Change the year for your needs.
I've implemented this solution exactly as written above and it is working, but inconsistently. When I am hovering over drop-down buttons, the CommandEnabler is firing no problem, but when I select elements in the model space, it fires less consistently (at the beginning it fires well for selecting two or three elements, but the more I click, the less it fires consistently, and at some points I can click numerous different elements without it firing once). Does this have to do with the current visibility of @FAIR59 's quickaccess button being changed without my knowledge? I was using the "Modify" check command, but had the same issue @mehdi.blanchard was having of selecting the same family type.
I've implemented this solution exactly as written above and it is working, but inconsistently. When I am hovering over drop-down buttons, the CommandEnabler is firing no problem, but when I select elements in the model space, it fires less consistently (at the beginning it fires well for selecting two or three elements, but the more I click, the less it fires consistently, and at some points I can click numerous different elements without it firing once). Does this have to do with the current visibility of @FAIR59 's quickaccess button being changed without my knowledge? I was using the "Modify" check command, but had the same issue @mehdi.blanchard was having of selecting the same family type.
Check out the new SelectionChanged event and Revit SDK sample in Revit 2023:
Application: SelectionChanged
Revit Platform: All
Revit Version: 2023.0
First Released For: 2023.0
Programming Language: C#
Skill Level: Beginning
Category: Basics
Type: ExternalApplication
Subject: SelectionChanged event
Summary: The sample implements IExternalApplication interface and subscribes SelectionChanged event in OnStartUp; the registered event handler will dump selected references related information to log files.
Check out the new SelectionChanged event and Revit SDK sample in Revit 2023:
Application: SelectionChanged
Revit Platform: All
Revit Version: 2023.0
First Released For: 2023.0
Programming Language: C#
Skill Level: Beginning
Category: Basics
Type: ExternalApplication
Subject: SelectionChanged event
Summary: The sample implements IExternalApplication interface and subscribes SelectionChanged event in OnStartUp; the registered event handler will dump selected references related information to log files.
Here is the Revit 2023 API functionality for this:
https://thebuildingcoder.typepad.com/blog/2022/04/whats-new-in-the-revit-2023-api.html#4.2.19
Here is the Revit 2023 API functionality for this:
https://thebuildingcoder.typepad.com/blog/2022/04/whats-new-in-the-revit-2023-api.html#4.2.19
Can't find what you're looking for? Ask the community or share your knowledge.