Power to the User (and Application)

Here is a little discussion that reminds me of the one on

prompting the user
to
pin a link and to export to IFC instead of trying to solve the whole thing programmatically.
It started from the following question:

Question: I want to display a warning message before deleting an element.
It is possible to capture the element before deleting it from the document?

We believe the DocumentChanged event can capture the deleted elements, i.e. after an element is deleted from the document.
But we want to capture it before the deletion.

Is there any way to achieve this?

Answer: You are right in your statement that the DocumentChanged event will report elements that were deleted after the fact.

As explained in the Revit API help file RevitAPI.chm, this event is raised whenever a Revit transaction is either committed, undone or redone. This is a read-only event, designed to allow you to keep external data in synch with the state of the Revit database. To update the Revit database in response to changes in elements, use the IUpdater framework.

The IUpdater framework is the only other element level notification mechanism. It will also enable you to determine when elements are being deleted and react to these changes, and it also allows you to make changes to the document and register them in the same transaction as the original changes that triggered the notification.

I do not see any way in which you can cancel the transaction, though, so I do not think that you can prevent the deletion from taking place even using the IUpdater interface.

Can you explain why you need to do this? Maybe we can find another approach to solve the issue.

Response: Actually we want to alert the user before deleting the elements from the document, particularly views.

Is there any other work around for this?

Answer: One approach that I can suggest that is not really a workaround at all, but a different way of looking at things, is to avoid doing any work on this yourself and let the Revit application do it for you, making use of the powerful features already available.

One such feature that exactly suits your requirement is the Undo feature … what you describe is exactly what it is there for.

Using the DocumentChanged notification, you can easily detect if any views have been deleted.

If that is the case, you can pop up a dialogue box saying “The view so-and-so has been deleted”, or “X views were deleted”, and “Are you really sure you want to do this? If not, please click the Undo button.”

I wrote about a similar way to use existing Revit functionality and work with it instead of against it in the post mentioned above on

prompting the user
.

This kind of thinking and development empowers the user and makes use of existing features instead of working against them.


Comments

6 responses to “Power to the User (and Application)”

  1. Hi Jeremy,
    How do i find the category of the deleted elements? when i try to get the Element from the ElementId it fails since the element has already been deleted.
    In my case i would like to warn users when they have delted a Floor.
    Regards, Kristian

  2. Dear Kristian,
    I was planning to test your assertion by looking at the Revit SDK ChangesMonitor sample which demonstrates the use of the DocumentChanged method.
    I assume that your question is based on using that event to be notified of the deleted elements. Looking at the ChangesMonitor DocumentChanged event handler, I note that it calls a helper method AddChangeInfoRow to list the added, deleted and modified element information in its modeless form. That method includes the following statements and comments which clearly tell you that the deleted element information is no longer accessible:
    // retrieve the changed element
    Element elem = doc.get_Element(id);
    . . .
    if (elem == null)
    // this branch is for deleted element due to the deleted element cannot be retrieved from the document.
    So the answer to your question is presumably no way, and that is as designed.
    There is an obvious workaround, though:
    The DocumentChanged event is a very simple notification after the fact. The transaction in which the document was modified has already been closed, you cannot do anything more about it yourself, and as we have seen, you cannot even query the deleted elements for their data.
    If you wish to access the document before the transaction is closed, there is a very powerful alternative possibility, the dynamic model update framework or DMU. It enables you to register an updater to be triggered by certain events, and also to react on these events within the same transaction that triggered them.
    It is demonstrated by the DynamicModelUpdate and DistanceToSurfaces SDK samples and discussed in
    http://thebuildingcoder.typepad.com/blog/2010/04/element-level-events.html#2
    Here is another DMU sample:
    http://thebuildingcoder.typepad.com/blog/2010/08/structural-dynamic-model-update-sample.html
    In your case, you can easily implement an updater that simply brings up a message box as described above, and register a trigger for it which reacts to the deletion of floors and nothing else.
    Your updater Execute method will be called while the transaction is still open, but unfortunately the deleted elements are no longer accessible anyway.
    Unfortunately, the properties of deleted elements cannot be accessed after deletion, even from updaters.
    Cheers, Jeremy.

  3. Jeremy,
    I came across this post when I tried to find ViewDeleted event. It’s said in the article “Using the DocumentChanged notification, you can easily detect if any views have been deleted”. I cannot figure out how. When view is deleted, elem is NULL using following code:
    Element elem = doc.get_Element(id);
    so how can I get element’s category at this time?
    Thanks

  4. Please delete my question. Looks you already answered the same question when I read the comments follow the article.

  5. Hi Jeremy,
    I tried “Dynamic Model Update” feature, still cannot get the deleted view when the update trigger is fired.
    my sample code in Execute method:
    public void Execute(UpdaterData data)
    {
    Document doc = data.GetDocument();
    foreach (ElementId id in data.GetDeletedElementIds())
    {
    Element element = doc.get_Element(id);
    if (element == null)
    {
    Debug.Print(“object deleted”);//that’s the problem!!!
    }
    else
    {
    Debug.Print(element.Category.Name);
    }
    }
    }

    It’s documented in Revit API guide chapter 25:

    25.2 The Execute method

    The purpose of the Execute() method is to allow your Updater to react to changes that have been made to the document, and make appropriate related. This method is invoked by Revit at the end of a document transaction in which elements that matched the UpdateTrigger for this Updater were added, changed or deleted.

    Does that mean when trigger is fired, the transaction already ends? Is there a way to get the inforamtion of deleted view? What I want is not undo function, but just want to take action with our linked database(external) if the view deleted is related.

  6. Dear LH,
    I am sorry to say that all you have access to is the element id of the deleted object, and that’s it.
    Even using the DMU, you cannot access the deleted object data.
    If it’s really important to remember information about deleted objects after deletion, you need to cache it somewhere beforehand.
    Since you are already maintaining an external cache of some information, are you possibly already including the view element ids there?
    Cheers, Jeremy.

Leave a Reply to LHCancel reply

Discover more from Autodesk Developer Blog

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

Continue reading