preselected elements highlighting

preselected elements highlighting

sobon.konrad
Advocate Advocate
939 Views
5 Replies
Message 1 of 6

preselected elements highlighting

sobon.konrad
Advocate
Advocate

I have been looking at Jeremy's post about locking down elements from Deleting. Here's the link: http://thebuildingcoder.typepad.com/blog/2011/11/lock-the-model-eg-prevent-deletion.html

 

I wanted to modify it a little bit. Right now it stores selected Ids and you can only ADD new ones to the selection but never remove any. My idea is to use the previously "protected" elemets to predefine the selection and then either add to that or remove from it before it gets stored back in _ProtectedIds. Here's my attempt, and currently it works as expected except that when prompted to select elements there is nothing highlighted. I am basically clearing _ProtectedIds and defning them again every time which is a little cumbersome. Any ideas will help:

 

#region Namespaces
using System;
using System.Collections.Generic;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
#endregion

namespace PreventDeletion
{
  /// <summary>
  /// External command to select elements 
  /// to protect from deletion.
  /// </summary>
  [TransactionAttribute(TransactionMode.Manual)]
  [RegenerationAttribute(RegenerationOption.Manual)]
  public class Command : IExternalCommand
  {
    public const string Caption = "Prevent Deletion";

    static List<ElementId> _protectedIds 
      = new List<ElementId>();

    static public bool IsProtected( ElementId id )
    {
      return _protectedIds.Contains( id );
    }

    public Result Execute(
      ExternalCommandData commandData,
      ref string message,
      ElementSet elements )
    {
      UIApplication uiapp = commandData.Application;
      UIDocument uidoc = uiapp.ActiveUIDocument;
      Document doc = uiapp.ActiveUIDocument.Document;

      IList<Reference> refs = null;

      try
      {
        // 1. get current contents of the _ProtectedIds.
        // 2. set current selection to those elements and highlight in view
        // 3. clear _Protected ids
        // 4. Prompt user selection
        // 5. Add re-defined user selection to _ProtectedIds.
          using (Transaction trans = new Transaction(doc))
          {
              trans.Start("test");
              uidoc.Selection.SetElementIds(_protectedIds);
              doc.Regenerate();
          }
          _protectedIds.Clear();
        // prompt user to add to selection or remove from it

        Selection sel = uidoc.Selection;

        refs = sel.PickObjects( ObjectType.Element, 
          "Please pick elements to prevent from deletion. " );
      }
      catch( OperationCanceledException )
      {
        return Result.Cancelled;
      }

      if( null != refs && 0 < refs.Count )
      {
        foreach( Reference r in refs )
        {
          ElementId id = r.ElementId;

          if( !_protectedIds.Contains( id ) )
          {
            _protectedIds.Add( id );
          }
        }
        int n = refs.Count;

        TaskDialog.Show( Caption, string.Format(
          "{0} new element{1} selected and protected "
          + " from deletion, {2} in total.",
          n, ( 1 == n ? "" : "s" ), 
          _protectedIds.Count ) );
      }
      return Result.Succeeded;
    }
  }
}
0 Likes
940 Views
5 Replies
Replies (5)
Message 2 of 6

sobon.konrad
Advocate
Advocate

So I have kept diggin and found that I can call PickOjects with a PreSelected list of Elements. That works now. The only trouble that I have at the moment is that this method doesn't allow me to prevent Assemblies from being deleted. As a matter of fact I can delete assemblies pretty freely. Any ideas on that? 

Here's current code: 

 

#region Namespaces
using System;
using System.Collections.Generic;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
#endregion

namespace PreventDeletion
{

    public class ElementFilter : ISelectionFilter
    {
        public bool AllowElement(Element e)
        {
            return true;
        }
        public bool AllowReference(Reference r, XYZ p)
        {
            return false;
        }
    }
    
    /// <summary>
    /// External command to select elements 
    /// to protect from deletion.
    /// </summary>
    [TransactionAttribute(TransactionMode.Manual)]
    [RegenerationAttribute(RegenerationOption.Manual)]
    public class Command : IExternalCommand
    {
        public const string Caption = "Prevent Deletion";
        
        static List<ElementId> _protectedIds 
          = new List<ElementId>();
        
        static public bool IsProtected( ElementId id )
        {
          return _protectedIds.Contains( id );
        }
        
        public Result Execute(
          ExternalCommandData commandData,
          ref string message,
          ElementSet elements )
        {
            UIApplication uiapp = commandData.Application;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Document doc = uiapp.ActiveUIDocument.Document;
            
            IList<Reference> refs = null;
            ElementFilter selFilter = new ElementFilter();
            List<Reference> preSelectedElems = new List<Reference>();

            if (_protectedIds.Count != 0)
            {
                foreach (ElementId id in _protectedIds)
                {
                    Reference elemRef = new Reference(doc.GetElement(id));
                    preSelectedElems.Add(elemRef);
                }
            }

            try
            {
                // prompt user to add to selection or remove from it
                Selection sel = uidoc.Selection;
                refs = sel.PickObjects(ObjectType.Element, selFilter, "Please pick elements to prevent from deletion.", preSelectedElems);
            }
            catch( OperationCanceledException )
            {
              return Result.Cancelled;
            }

            _protectedIds.Clear();

            if( null != refs && 0 < refs.Count )
            {
                foreach( Reference r in refs )
                {
                    ElementId id = r.ElementId;
                    
                    if( !_protectedIds.Contains( id ) )
                    {
                      _protectedIds.Add( id );
                    }
                }
                int n = refs.Count;
                
                TaskDialog.Show( Caption, string.Format(
                  "{0} new element{1} selected and protected "
                  + " from deletion, {2} in total.",
                  n, ( 1 == n ? "" : "s" ), 
                  _protectedIds.Count ) );
            }
            return Result.Succeeded;
        }
    }
}
Message 3 of 6

sobon.konrad
Advocate
Advocate

This seems to be working just fine:

 

using System;
using System.Collections.Generic;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;

namespace PreventDeletion
{
    // Create Elment Filter that passes all elements through
    public class ElementFilter : ISelectionFilter
    {
        public bool AllowElement(Element e)
        {
            return true;
        }
        public bool AllowReference(Reference r, XYZ p)
        {
            return false;
        }
    }

    /// <summary>
    /// External command to select elements 
    /// to protect from deletion.
    /// </summary>
    [TransactionAttribute(TransactionMode.Manual)]
    [RegenerationAttribute(RegenerationOption.Manual)]
    public class Command : IExternalCommand
    {
        public const string Caption = "Prevent Deletion";

        static List<ElementId> _protectedIds
          = new List<ElementId>();

        static public bool IsProtected(ElementId id)
        {
            return _protectedIds.Contains(id);
        }

        public Result Execute(
          ExternalCommandData commandData,
          ref string message,
          ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Document doc = uiapp.ActiveUIDocument.Document;

            IList<Reference> refs = null;
            ElementFilter selFilter = new ElementFilter();
            List<Reference> preSelectedElems = new List<Reference>();

            if (_protectedIds.Count != 0)
            {
                foreach (ElementId id in _protectedIds)
                {
                    Reference elemRef = new Reference(doc.GetElement(id));
                    preSelectedElems.Add(elemRef);
                }
            }

            try
            {
                // prompt user to add to selection or remove from it
                Selection sel = uidoc.Selection;
                refs = sel.PickObjects(ObjectType.Element, selFilter, "Please pick elements to prevent from deletion.", preSelectedElems);
            }
            catch (OperationCanceledException)
            {
                return Result.Cancelled;
            }

            _protectedIds.Clear();

            if (null != refs && 0 < refs.Count)
            {
                foreach (Reference r in refs)
                {
                    ElementId id = r.ElementId;

                    if (!_protectedIds.Contains(id))
                    {
                        _protectedIds.Add(id);
                    }
                }
                int n = refs.Count;

                TaskDialog.Show(Caption, string.Format(
                  "{0} new element{1} selected and protected "
                  + " from deletion, {2} in total.",
                  n, (1 == n ? "" : "s"),
                  _protectedIds.Count));
            }
            return Result.Succeeded;
        }
    }
}

The only thing that I am curious about at this point is if there is a way to create a filter needed by the UpdateRegistry.AddTrigger so that it doesn't stop anything from being added to the selection. For now I use a ElementClassFilter set to Dimension type and inverted so that it only allows Dimensions to be deleted. Iam not too concerned about preventing people from deleting annotation so this works. It would be nice to know if there is a better way to do this though. 

 

using System;
using System.Collections.Generic;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;

namespace PreventDeletion
{
    class App : IExternalApplication
    {
        public Result OnStartup(UIControlledApplication a)
        {
            DeletionUpdater deletionUpdater
              = new DeletionUpdater(a.ActiveAddInId);

            UpdaterRegistry.RegisterUpdater(
              deletionUpdater);

            ElementClassFilter filter
              = new ElementClassFilter(
                typeof(Dimension), true);

            UpdaterRegistry.AddTrigger(
              deletionUpdater.GetUpdaterId(), filter,
              Element.GetChangeTypeElementDeletion());

            //FailureDefinitionRegistry

            return Result.Succeeded;
        }

        public Result OnShutdown(UIControlledApplication a)
        {
            return Result.Succeeded;
        }
    }
}

 

Thank you,

 

 

0 Likes
Message 4 of 6

jeremytammik
Autodesk
Autodesk

Dear Konrad,

 

Thank you for your query and sharing your iterative approach towards a solution.

 

Using the Dynamic Model Updater framework DMU to prevent specific elements from being deleted sounds like a perfectly viable approach to me.

 

Also, using the inverted ElementClassFilter set to Dimension type makes total sense, depending on what exactly you wish you achieve.

 

It sounds to me like you have resolved all your open questions now. 

 

Would you like to share the entire solution to make it easier to understand how it all fits together?

 

Thank you!

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 5 of 6

sobon.konrad
Advocate
Advocate

Jeremy,

 

The goal was to allow ANY element to be "locked down" hence my question about a different filter that will allow all elements to pass. My current solution with inverted Dimension filter is "good enough" but not quite what I was shooting for. 

 

Also, at the moment the "preselection"/highlighting works great on Walls, Furniture etc. but doesn't highlight elements in Assemblies for example. So if I add an Assembly to the "lock down list" and next time i access it, it pre-selects the assembly but its not visually apparent on the screen since assembly members are not highlighted. Is my only option to iteratively check Category of each added element and if its an Assembly just get all its elements while adding those to the "lock down" as well? 

 

Any ideas on alternative approaches to this are welcome. I will post the full solution when this last issue is addressed. 

 

0 Likes
Message 6 of 6

jeremytammik
Autodesk
Autodesk

Dear Konrad,

 

Thank you for your explanation.

 

I must admit that I am not quite clear on what you mean by 'locked down', and how that is supposed to be represented by your filter.

 

Looking forward to hearing how you complete the solution, and I hope that will help my understanding.

 

Thank you!

 

Good luck!

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes