« ElementId Parameter Value | Main | Public Revit 2011 SDK Posting »

April 14, 2010

Comments

Object Level events are not available in the latest SDK. Can you post the latest changemonitor solution file?

Thanks

Dear Srinivasan,

I assume you mean "are now available".

The latest version of the SDK including the ChangesMonitor sample is publicly available at

http://www.autodesk.com/developrevit

The file details from that location are:

2010-04-28 13:42 110,098,139 revit2011sdk.exe

The versions of the SDK included with the Revit Architecture, MEP and Structure products are:

2010-03-26 21:23 110,416,595 RevitSDK.exe

It does not really make any difference which SDK you use. The SDK really just provides information and samples. The actual API is completely defined by and contained in the Revit API assemblies which are provided with the Revit product, in the Program subdirectory of the main installation folder where Revit.exe also resides. On my system they are

2010-03-26 20:27 15,494,656 RevitAPI.dll
2010-03-26 20:28 711,168 RevitAPIUI.dll

I have not compared the two versions of the SDK, but I think the differences are negligible.

On my system I installed the one coming with the product, i.e. the 110,416,595 byte version, and I have not noticed any problems with that.

Cheers, Jeremy.

Hi Jeremy

Iam mean that the eventsmonitor sample in the SDK doesn't show any function related to the document changed event.

I wanted to test with the object level event & was looking for some sample.

Srini

Dear Srini,

I do not know when you say "the eventsmonitor sample". Do you mean the ChangesMonitor sample, which demonstrates the use of the Application.DocumentChanged event? If yes, then please see above for all the details. If not, please clarify.

Cheers, Jeremy.

When you mentioned "Element Level", I was hoping that included element selection events, but that does not seem to be the case.

As a work-around, I created this class that subscribes to the application "Idle" event and checks for selection changes. Given that its an "Idle" event, I have tried to be as efficient as possible at figuring out whether a change has happened, but there may be a simpler way?

Usage:
public Autodesk.Revit.UI.Result OnStartup(UIControlledApplication application) {
selectionChangedWatcher = new SelectionChangedWatcher(application);
selectionChangedWatcher.SelectionChanged += new EventHandler(selectionChangedWatcher_SelectionChanged);
...

Code:

public class SelectionChangedWatcher
{
public event EventHandler SelectionChanged;
protected void Call_SelectionChanged() {
if (SelectionChanged != null) {
SelectionChanged(null, new EventArgs());
}
}

private UIApplication uiApplication;
private List m_Selection;
public List Selection {
get {
return m_Selection;
}
set {
m_Selection = value;
}
}
public SelectionChangedWatcher(UIControlledApplication application) {
application.ControlledApplication.DocumentOpened += new EventHandler(ControlledApplication_DocumentOpened);
application.Idling += new EventHandler(application_Idling);
}

void ControlledApplication_DocumentOpened(object sender, Autodesk.Revit.DB.Events.DocumentOpenedEventArgs e) {
if (uiApplication == null) {//--doesn't really need to listen to documentOpened event, but this seems the easiest way to get a reference to the UIApplication
uiApplication = new UIApplication(e.Document.Application);
}
}

private string selectionUID;
void application_Idling(object sender, Autodesk.Revit.UI.Events.IdlingEventArgs e) {
if (uiApplication == null) return;
if (uiApplication.ActiveUIDocument == null) return;
SelElementSet selected = uiApplication.ActiveUIDocument.Selection.Elements;
if (selected.Size == 0) {
if (m_Selection != null && m_Selection.Count > 0) {
HandleSelectionChange(selected);
}
} else {
if (m_Selection == null) {
HandleSelectionChange(selected);
} else {
if (m_Selection.Count != selected.Size) {
HandleSelectionChange(selected);
} else {//--count is the same... compare UID to see if selection has changed
string uid = "";
foreach (Element elem in selected) {
uid += "_" + elem.Id;
}
if (uid != selectionUID) {
HandleSelectionChange(selected);
}
}
}
}
}

private void HandleSelectionChange(SelElementSet selected) {
m_Selection = new List();
selectionUID = "";
foreach (Element elem in selected) {
m_Selection.Add(elem);
selectionUID += "_" + elem.Id;
}
Call_SelectionChanged();
}
}

Sorry for the unreadable code. Here are some PasteBin URLs:
Class: http://visualstudio.pastebin.com/X5rBXSA6
Usage: http://visualstudio.pastebin.com/aNwEFRkZ

Dear Ken,

Thank you for your query with the interesting idea and the source code.

No worry about its readability, one can easily copy and paste it into a Visual Studio project to automatically reformat it.

Thank you also for the interesting PasteBin URLs. I was not previously aware of this possibility.

Regarding the element selection events, you are correct in your assessment that these are currently not provided by the Revit API.

Your use of the Idling event to implement a work-around sounds like a brilliant idea to me.

Would you like to provide a complete little sample solution with the code and a minimal testing script, so I can run through it with a minimum of fuss?

I would love to promote this to a full-fledged blog post to increase awareness of it and provide an additional example of using the Idling event in creative ways including stopping gaps in the existing API. My contact details are listed in the page 'About the Author'.

I tried to contact you directly using the link attached to your name above, but that does not work for me, unfortunately.

Thank you!

Cheers, Jeremy.

Hi all,

As many others Revit API users, I miss the "element selection changed" API access.

As mentioned in this post, there are several solutions, each having some caveats :

1. Use the OnIdling event to check current selection.
This may not be reliable, because there is no guaranty it will be fired by Revit.
Secondly, this is an asynchronous method.

2. Use a Timer to raise an event at a specified interval.
More reliable, but still asynchronous and the more accurate it is (i.e. shorter timer delay), the more unneeded event are generated.

3. There is a third method that solve all the above "issues".
In Revit, when the user select/unselect an object, there is a special ribbon tab that dynamically changes, its name is "Modify".

Knowing that, and using the standard Autodesk assembly "AdWindows.dll", we can register an event that will be fired when this Tab's title changes.
Here it is :

foreach (Autodesk.Windows.RibbonTab tab in Autodesk.Windows.ComponentManager.Ribbon.Tabs)
{
if (tab.Id == "Modify")
{
tab.PropertyChanged += PanelEvent;
break;
}
}

void PanelEvent(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (sender is Autodesk.Windows.RibbonTab)
{
if (e.PropertyName == "Title")
{
//selection changed !
}
}
}

Not the cleanest way I admit, but until Autodesk adds the relevant API methods, this is (for me) the best.

Dear Vilo,

That is an absolutely superb idea and brilliant little workaround.

I'll promote it to a main blog post asap.

Thank you!

Cheers, Jeremy.

Hi Jeremy,

Feel free to make what you want with this workaround ;o)

Since I posted, I can added the following elements :

- The test "if (sender is Autodesk.Windows.RibbonTab)" is not needed.

- The Tab's name is not dependent to current language.
My Revit is in french, and the tab's name is still "Modify" at start (then it changes according to current selection of course).

- There is actually a limitation I'm working on : the event is not fired after selecting the 3rd element (and 4th, 5th, ...) in a multiselection.

Dear Vilo,

Thank you for your update, permission to share and pointer to the current limitations.

I implemented a new external command for The Building Coder samples exercising this:

https://github.com/jeremytammik/the_building_coder_samples/blob/master/BuildingCoder/BuildingCoder/CmdSelectionChanged.cs

Obviously it would normally not be used in a command, but on startup in an external application.

Cheers, Jeremy.

Dear Vilo,

Thank you again for your wonderful idea!

I published it as a stand-alone post now:

http://thebuildingcoder.typepad.com/blog/2015/03/element-selection-changed-event.html

Cheers, Jeremy.

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been posted. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment

Your Information

(Name and email address are required. Email address will not be displayed with the comment.)

Jeremy Tammik

AboutTopicsIndexSource