Highlight Elements

I arrived in Boston and am now acclimatising in preparation for the

AEC DevCamp
conference
(web site) starting
on Monday and the

DevLabs
in Waltham following afterwards
(register).

Meanwhile, here is a quick

question from Soub
that
we have actually provided a solution for a couple of times in the past but not explicitly pointed out yet.

Question: I have a question related to the API for highlighting elements in Revit Architecture based on the Element ID input.
Could you please help me by explaining how to highlight multiple elements based on IDs?

Answer: There is really no difference between highlighting a single element or multiple ones.
All you need to do is add them to the current selection set managed by the Revit UI document, or to the third argument to the Execute method, and then return a Cancelled or Failed result code.

An example of the first approach is provided by the command

highlighting south facing walls
.
The main lines of interest there in this context are the ones accessing the current selection set, adding specific elements to it, and setting the property to the new collection:


SelElementSet selElements = Document.Selection.Elements;
 
IEnumerable<Wall> walls = CollectExteriorWalls();
 
foreach( Wall wall in walls )
{
  XYZ exteriorDirection = GetExteriorWallDirection( wall );
 
  bool isSouthFacing = IsSouthFacing( exteriorDirection );
 
  if( isSouthFacing )
  {
    selElements.Add( wall );
  }
}
 
Document.Selection.Elements = selElements;

The code presented there is based on Revit 2010.
It has been updated for the Revit 2011 API in the DirectionCalculation SDK sample and now looks like this:


  UIDocument uiDoc = new UIDocument( Document );
 
  Autodesk.Revit.UI.Selection.SelElementSet
    selElements = uiDoc.Selection.Elements;
 
  IEnumerable<Wall> walls
    = CollectExteriorWalls();
 
  foreach( Wall wall in walls )
  {
    XYZ exteriorDirection
      = GetExteriorWallDirection( wall );
 
    if( useProjectLocationNorth )
    {
      exteriorDirection
        = TransformByProjectLocation(
          exteriorDirection );
    }
 
    bool isSouthFacing
      = IsSouthFacing( exteriorDirection );
 
    if( isSouthFacing )
      selElements.Insert( wall );
  }
 
  // Select all walls which had the proper direction.
  uiDoc.Selection.Elements = selElements;

As said, you can also highlight elements graphically by adding them to the third argument of an external command Execute method and then returning a Cancelled or Failed result code:


public Result Execute(
  ExternalCommandData revit,
  ref string message,
  ElementSet elements )
{
  // . . .
 
  Element e;
 
  // . . .
 
  elements.Insert( e );
  return Result.Failed;
}

This is demonstrated by the Lab1_2_CommandArguments of the

Revit API introduction labs
.


Comments

37 responses to “Highlight Elements”

  1. Hi Jeremy,
    I had trouble with displaying Modify ribbon after I select elements from code. I found out, that if I use doc.BeginTransaction() and doc.EndTransaction() right after, it works perfectly.
    Now I had to reinstal Revit Architecture 2010 and the problem reappeared. I tried few different selection methods, but nothing helped. Is there an “update ribbon” method or something similar, that would solve the thing?

  2. Dear Jonz,
    Nope, the Revit API does not provide any methods to updated the ribbon or refresh the user interface in any way, as far as I know. Revit seems to assume that it can take care of that internally. I have also not heard of any similar issues in the past. Is this all in Revit 2010? Have you tried it in 2011?
    Cheers, Jeremy.

  3. Hi Jeremy,
    this is in Revit 2010, I haven’t been able to run the command in 2011 yet, since I have a problem selecting elements from model.
    Since I am talking to a guru, I would like to ask you, if you know, what is going on with new selection method. In 2010 for example it was:
    ElementIterator ei = _document.Elements;
    ei.Reset();
    while (ei.MoveNext())
    {
    // do something – worked like charm
    }
    In 2011 I use:
    FilteredElementCollector collector = new FilteredElementCollector(_document);
    ICollection elements = collector.WhereElementIsNotElementType().ToElements();
    foreach (Element e in elements)
    {
    try
    {
    // do something – I need try-catch, because sometimes e != null, but the properties of e are null (e.g. e.Category == null)
    }
    catch
    {}
    }
    Is that correct approach, or did I miss something (e.g. new RemoveNullElementsFilter or something similar :)?
    Cheers, jonz

  4. Dear Jonz,
    In principle you are completely right, but there is room for improvement on two counts:
    1) You do not have to convert your collector to an ICollection if you do not want to for other reasons. The collector itself already provides an IEnumerator interface, so you can directly say ‘foreach Element e in collector’.
    2) If you are expecting some elements to have a null category property, which is a sensible expectation and also was so in 2010, then you should NOT, DEFINITELY NOT, use an expception to handle that case. An exception is for handling exceptional cases, not an expected situation. Just test whether the category is null instead. An exception is a hundred times more expensive, both in time and other resources.
    So you code might look like this:
    FilteredElementCollector collector = new FilteredElementCollector(_document);
    collector.WhereElementIsNotElementType();
    foreach( Element e in collector )
    {
    if( null != e.Category )
    {
    // do something
    }
    }
    Cheers, Jeremy.

  5. Purnima Avatar
    Purnima

    Hi,
    I am making a call to my .NET application from Revit. (setting up the information in ini file)
    As soon as my .NET application opened, it is making a call to the following method.
    public ExternalCommandData m_CommandData; // class member
    public IExternalCommand.Result Execute(Autodesk.Revit.ExternalCommandData revit, ref string message, ElementSet elements)
    {
    m_CommandData = revit;
    FormHighlight l_FormHighlight = new FormHighlight();
    l_FormHighlight.Show();
    Document l_Doc = m_CommandData.Application.ActiveDocument;
    ElementId l_ElementId = new ElementId();
    l_ElementId.Value = 157145;
    Element l_Element = l_Doc.get_Element(ref l_ElementId);
    l_Doc.ShowElements(l_Element);
    return IExternalCommand.Result.Succeeded;
    }
    Here I have hardcoded the element id value and it perfectly highlighing the relevent Element on Revit.
    In my .NET application I have a Data Grid where I will have the set of records with Element id, Date, Floor Level, Direction, Volume, Length, etc., and upon clicking on the row, I will pick the element id and passit to the l_ElementId.Value = >
    Following is the code piece inside the Data Grid Cell Click event. Here “m_CommandData” I have already set the value globally inside Execute method.
    private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
    {
    Document l_Doc = m_CommandData.Application.ActiveDocument;
    ElementId l_ElementId = new ElementId();
    l_ElementId.Value = Convert.ToInt32(dataGridView1.Rows[e.RowIndex].Cells[0].Value);
    Element l_Element = l_Doc.get_Element(ref l_ElementId);
    l_Doc.ShowElements(l_Element);
    }
    But I am getting the error which says m_CommandData is null.
    Can you please help me how to sort out the issue?
    Thank you,
    Purnima

  6. Dear Purnima,
    Your issue looks like a fundamental problem of understanding the structure of our own application.
    As far as I can tell, you have made m_CommandData a class member of your command class. The data grid view is presumably located in a different class, so it has different class members. If you want to access the document from the data grid view class, you will need to pass in that information somehow from the command class.
    I suggest learning more basic .NET technology and object oriented design principles before proceeding any further with this :-)
    Cheers, Jeremy.

  7. Purnima Avatar
    Purnima

    Dear Jeremy,
    Thank you so much for the guidance!
    Actually I am in the learning process of .NET technology.
    In my project the m_CommandData and DataGrid are in the same class. So is there a way to resolve the issue?
    Thank you,
    Purnima

  8. Dear Purnima,
    If they are in the same class, then you should be able to simply set the global class variable
    m_CommandData = commandData
    in the Execute method, and access the non-null value of m_CommandData elsewhere in the class.
    Please be aware that you can only access the m_CommandData functionality before you return from the Execute method. Afterwards, you are no longer in a valid Revit API context. This topic is discussed in many places in this blog, e.g. most recently in
    http://thebuildingcoder.typepad.com/blog/2010/07/modeless-loose-connectors.html
    Cheers, Jeremy.

  9. Hi Jeremy,
    Th code line
    uiDoc.Selection.Elements = selElements;
    Doesn’t work for some time and work for some time. So for this i used the code like as below..
    uiDoc.Selection.Elements.Clear();
    uiDoc.Selection.Elements = totalEmelemnt; //ElementSet
    uiDoc.ShowElements(totalEmelemnt);
    Now its working perfectly for me.
    Thank You
    Sandeep

  10. Dear Sandeep,
    Thank you very much for the hint!
    I am very glad that you found a solution!
    You are using a rather strange spelling in your variable naming: totalEmelemnt;
    Happily, the computer does not care :-)
    Cheers, Jeremy.

  11. Actually there is one method for refreshing currentView =>
    ActiveUIDocument.RefreshActiveView()
    good luck, and very thanks for great tutorials !!!

  12. Dear Agnius,
    Right you are, thank you very much for pointing that out! And for your appreciation!
    Cheers, Jeremy.

  13. Hi Jeremy,
    I tried the first method to highlight the element by adding them to the current selection. and I only need to highlight one element. When I invoked : m_uiDocument.Selection.Elements = selectElements; it worked.
    But on the Revit Architecture (I use 2012 version). the “properties” window the the left it doesn’t change to the selected element’s property info and still the before one. I don’t know how to let it change.
    thank you,
    Jeremy

  14. Dear Jinshou Lee,
    Sorry, I am not aware of a reliable method to force this update. Maybe you can flush the view, somehow. Maybe the UIDocument RefreshActiveView method can help:
    http://thebuildingcoder.typepad.com/blog/2012/04/devcamp-and-refresh-display-for-a-kinetic-facade.html
    Please let us know if you find a solution.
    Thank you!
    Cheers, Jeremy.

  15. Hi, Jeremy.
    What a pity. I tried to invoke UIDocument RefreshActiveView method after add element to m_uiDocument.Selection.Elements. But still can not update the “Properties” window on the Revit Architecture 2012. I think maybe RefreshActiveView method can only refresh the view but the “Properties” window isn’t belong to the view. Thank you.
    Best Regards,
    Jinshou.

  16. Dear Jinshou,
    Ah, that’s a shame indeed. There may be something else that can be done to refresh that window. For instance, you could try moving the element by a small distance, and then moving it back again.
    Please let us know if you find a solution. Thank you!
    Cheers, Jeremy.

  17. Hi,Jeremy,
    thanks for your help hint, but I tried moving the element and still can not update the ‘properties’ window info.
    By the way, I have another question. I wanted to get every view’s elements(like walls,windows…), so looped every view I invoked: FilteredElementCollector windowCollector = new FilteredElementCollector(m_document, curView.Id)
    .OfCategory(BuiltInCategory.OST_Windows); but after executing this statement will consume much memory and as a result throw a out of memory exception (big model). but if I invoked:windowCollector = new FilteredElementCollector(m_document)
    .OfCategory(BuiltInCategory.OST_Windows); to get all document’s elements and it consumed almost no memory. I don’t know if it is bug of revit. if get all document’s elements first, I don’t know which elements is visible in every views.
    Thank you.
    Best Regards,
    Jinshou

  18. Dear Jinshou,
    Oh dear. Well, there are thousands of other things you can try to refresh the properties window. Switch the discipline. Switch the view. Call ShowElements. Be creative.
    The other issue sounds very worrying. On the other hand, nobody else has reporting any such thing, so there is probably something else wrong somewhere.
    If the problem persists, we will need a reproducible case to look at.
    Cheers, Jeremy.

  19. Hi,Jeremy,
    Thank you for your hint, I will try to refresh the properties window by other way.
    the second issue. I tried write the follow simple funtion to invoke:
    private void test(){
    FilteredElementCollector viewCollector = new FilteredElementCollector(m_document).OfCategory(BuiltInCategory.OST_Views);
    foreach (Element viewElem in viewCollector)
    {
    Autodesk.Revit.DB.View curView = viewElem as Autodesk.Revit.DB.View;
    if(!FilteredElementCollector.IsViewValidForElementIteration(m_document, curView.Id)) continue;
    FilteredElementCollector viewElems = new FilteredElementCollector(m_document,curView.Id).WhereElementIsNotElementType();
    }
    }
    after running test() increased about 800MB of revit(model has 217 views and every views has the average of about 8000 elements). Whether it is normal situation to consume so much memory. Or if should invoke some function to release the collector. but if I changed the last statement that remove the second param ‘curView.id’ to run again. test() consumed very little memory, it also was invoked 217 times.
    And if run the changed test() to get all document’s elements. Whether I can classify the elements to every views, I can’t find the reference method to invoke.Thank you.
    Best regards,
    Jinshou

  20. Dear Jinshou,
    If you are an ADN mmeber, please submit a DevHelp Online case for this.
    We need a reproducible case to explore this, i.e. a complete single-click ready-to-run solution plus sample model.
    Cheers, Jeremy.

  21. Hi, Jeremy
    OK, thank you.
    Best regards,
    Jinshou

  22. Hi, Jeremy,
    I tried my best to update the ‘properties’ window info and still failed. Whether ADN member can get more API to solve the problem.
    Thank you.
    Best Regards,
    Jinshou.

  23. Dear Jinshou,
    Sorry to hear that you did not yet find a solution.
    You can submit a wish list item for it in the Revit API wish list survey:
    http://thebuildingcoder.typepad.com/blog/2012/05/revit-and-navisworks-api-wishlist-surveys.html
    Cheers, Jeremy.

  24. Hi, Jeremy,
    I found how to update the ‘properties’ window, And If I invoke the function OpenAndActivateDocument()of class UIApplication firstly, then highlight elements like this blog you wrote, the ‘properties’ window can be updated.
    But firstly you should guarantee that the document you want to highlight should not be the active document, so I create a empty rvt file, then invoke OpenAndActivateDocument() to active, now the document which elements want to highlight isn’t active document, then I invoke OpenAndActivateDocument() again to active the document which elements want to highlight and highlight elements like this blog you wrote, and don’t forget to close the empty rvt file at last. By this way can refresh the ‘properties’ window info.

  25. Dear Jinshou,
    Thank you for the interesting tip, which I promoted to a main blog post:
    http://thebuildingcoder.typepad.com/blog/2012/09/updating-properties-and-announcing-revit-lt.html#2
    We do have an internal wish list item for this functionality, and I added a note of your solution there as well for future reference.
    Cheers, Jeremy.

  26. Dear Jeremy:
    I am trying to highlight a face on a wall, but selection sets only allow elements.
    Is it possible to highlight just a face of a Wall?
    Thank you very much.
    José Ignacio Montes

  27. Dear José Ignacio,
    You could prompt the user to select elements and request face subelements.
    That would highlight faces.
    It would require user interaction, though.
    Without user interaction, I am not aware of any such possibility.
    Cheers, Jeremy.

  28. Carlos Collado Avatar
    Carlos Collado

    Dear Jeremy,
    I am trying to highlight a room with this method but only works after ExternalCommand end. Are there any way to do it before?
    Thanks a lot.

  29. Dear Carlos,
    Yes, it should be possible to update the model graphics before terminating the command.
    You can try to call document Regenerate, or terminate a transaction.
    The latter is more expensive.
    The DisplacementElementAnimation sows something like this:
    http://thebuildingcoder.typepad.com/blog/2013/08/animation-and-the-displacementelement-class.html
    So does the kinetic facade sample, which may actually be exactly what you are looking for:
    http://thebuildingcoder.typepad.com/blog/2012/04/devcamp-and-refresh-display-for-a-kinetic-facade.html
    Cheers, Jeremy.

  30. Hello Jeremy,
    My plugin will show a Window From with different rooms properties listed on it. What I want is to highlight the room when I select the room from GUI. Is there any simple way to do it?
    The method mentioned in your code can highlight an element only after the Execute() function is finished. However, I want the element to be highlighted in between (i.e., GUI is still running)

  31. Hi Jeremy,
    I am a new student of Revit API and your blog is being extremmelly helpfull for me. At the moment I am trying to make my addin to highlight some specific element in revit, but i am really struggled some far.
    My problem are:
    I use “TaskDialog.Show(“Selected Element”, info);” to show the specific element in zoom-in-mode but the element still haven’t selected (highlighted in blue). So Is there any codes to do that?
    My other question is How can I create a API that can open the Type Property once I run it.
    Thanks in advance.
    Ricky

  32. Dear Ricky,
    Thank you for your appreciation. I am glad you find it useful.
    I can think of two possibilities off-hand. Not sure that they still work, though.
    1. Specify the Revit selection set, e.g. using the Selection.SetElementIds method.
    2. Not so elegant… add the elements you want highlighted to the ElementSet argument passed in to your external command Execute method, and return Result.Cancelled or Result.Failed. That causes them to be highlighted. This method is used by the south facing windows sample:
    http://thebuildingcoder.typepad.com/blog/2010/01/south-facing-walls.html
    I hope this helps.
    Cheers, Jeremy.

  33. Hi Jeremy,
    Thanks for your help and I would give it a try.
    Is there any command that could open the type property under the
    “edit type” of each element.
    Thanks
    Ricky

  34. Dear Ricky,
    Only Revit can activate the property panel.
    That is actually obvious, once you think about it.
    However, if you can programmatically activate an element, then Revit may display its properties.
    In this case, since you are after type properties, you would have to set the element type as the active selected element.
    You can try to do that manually through the Manage > Select by ID, and programmatically using the Selection.SetElementIds method.
    I have heard that Revit sometimes does not update the property panel even when the selection has changed, though, so I cannot guarantee that will work.
    Please let us know how you get on.
    If you solve this, it may be worth a blog post.
    Thank you!
    Cheers, Jeremy.

  35. Dear Jeremy,
    Thanks for your response.
    I have selected the element by its ID and showed it on the screen using the command “ShowElements(id);”, however it doesn’t highlight the element(in blue). Do you know any command that would help with that?
    I have tried the “Selection.SetElementIds” method but it still doesn’t show the element.
    Thanks for your help
    Kind regards,
    Ricky

  36. Dear Jeremy,
    Thanks for your response.
    I have selected the element by its ID and showed it on the screen using the command “ShowElements(id);”, however it doesn’t highlight the element(in blue). Do you know any command that would help with that?
    I have tried the “Selection.SetElementIds” method but it still doesn’t show the element.
    Thanks for your help
    Kind regards,
    Ricky

  37. Dear Ricky,
    The instance element may be visible and highlighted on the screen.
    Its type is never visible on the screen and therefore cannot be highlighted.
    You will have to decide which of the two you want.
    You cannot have both simultaneously.
    This is a typical case where it some end user experience helps understand the situation better.
    If you want to display type properties to the user, it may be more effective to define your own user interface instead of using the standard Revit property panel.
    Cheers, Jeremy.

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading