View close event - Identify view is closed

View close event - Identify view is closed

sankar_g
Enthusiast Enthusiast
1,508 Views
6 Replies
Message 1 of 7

View close event - Identify view is closed

sankar_g
Enthusiast
Enthusiast

Hi All,

I would like to do some operation when a view is closed in the document. 

I tried with combination of view activated event and uiDocument.GetOpenUIViews(), but unfortunately it returns the closed view also in the list.

Is there any other workaround to identify view is closed.

0 Likes
1,509 Views
6 Replies
Replies (6)
Message 2 of 7

Moustafa_K
Collaborator
Collaborator

Well! try this. it is a bit long but tested

 

In short:

you need to do a couple of event registers to distinguish between what is currently UIViews are opened and what are closed. So we need to store the currently opened UIViews ids and keep adding newly created/opened ones. as well as to remove those which are closed. 

 

Also, we need to use Revit IdlingEvent to trigger an event, since Revit is not busy, meaning all views are now closed.

Hence, when Revit is in Idle state we compare the currently opened UIViews against what we stored then we run our Math. 

 

One drawback of the below, if you closed a view that is not the current view. the below algorithm won't work. but eventually will work when you switch to another view. but I trust you can cover this drawback part.

 

see the below code and let us know if something is not clear.

 

as a hint, you can start registering all these events on Revit Start at the IExternalApplication class. or via IExternalCommand depends on how your strategy is.

 

ViewClosed_Event WorkaroundViewClosed_Event Workaround

 

Summary:

1. Register DocumentOpened all Available UIViews Id

2. Register on ViewActivating To store new created View to the ViewIds store list

3. Register on ViewActivated the comparison between current opened Views against the closed using the power of Idling event

4. unregister all events once you no more need that

 

Detail:

1. Register DocumentOpened all Available UIViews Id

 

m_uiapp.Application.DocumentOpened += delegate{
viewids = m_uidoc.GetOpenUIViews().Select(o => o.ViewId).ToList();
};

 

 

2. Register on ViewActivating To store new created View to the ViewIds store list

 

m_uiapp.ViewActivating += M_uiapp_ViewActivating;

private void M_uiapp_ViewActivating(object sender, Autodesk.Revit.UI.Events.ViewActivatingEventArgs e)
        {
            if (!viewids.Contains(e.NewActiveView.Id))
                viewids.Add(e.NewActiveView.Id);
        }

 

 

3. Register on ViewActivated the comparison between current opened Views against the closed using the power of Idling event

 

 UT_Rvt.m_uiapp.ViewActivated += M_uiapp_ViewActivated;

  private void M_uiapp_ViewActivated(object sender, Autodesk.Revit.UI.Events.ViewActivatedEventArgs e)
        {
            UT_Rvt.m_uiapp.Idling += M_uiapp_Idling;
        }

 private void M_uiapp_Idling(object sender, Autodesk.Revit.UI.Events.IdlingEventArgs e)
        {
            var ids = m_uidoc.GetOpenUIViews().Select(o => o.ViewId);
            List<ElementId> closedids = new List<ElementId>();
            foreach (var id in viewids)
            {
                if (ids.Contains(id)) continue;
                ViewIsClosed(id);
                 closedids.Add(id);
            }
            foreach (var id in closedids)
            {
                viewids.Remove(id);
            }
            // Stop Idling from repeating itself, since we are done here.
            m_uiapp.Idling -= M_uiapp_Idling;
        }

  private void ViewIsClosed(ElementId id)
        {
            var view = m_doc.GetElement(id) as View;
            TaskDialog.Show("Closed", $"View is Closed {id} {view.ViewName}");
        }

 

 

and finally, don't forget to unregister all events once you no more need that

 

 private void UnregisterEvents()
        {
            m_uiapp.Application.DocumentOpened -= Application_DocumentOpened;
            m_uiapp.ViewActivating -= M_uiapp_ViewActivating;
            m_uiapp.ViewActivated -= M_uiapp_ViewActivated;
        }

 

 

Hope this helps.

 

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
Message 3 of 7

sankar_g
Enthusiast
Enthusiast

Hi mostafa90,

Thank you for your reply.

I have solved the issue with ViewActivated event and MainWindow object. Idling event will produce performance issues so I tried the solution without idling.

As mentioned in your reply, we can’t get the trigger for closed view that is not the current view and this code also have the same drawback.

 

private bool IsViewClosed(View view, UIDocument uiDocument)
        {
            var uiView = uiDocument.GetOpenUIViews().ToList().FirstOrDefault(v => v.ViewId == view.Id);
            if (uiView == null)
            {
                return true;
            }
            else
            {
                var mainWindow = UIFramework.MainWindow.getMainWnd();
                if (mainWindow == null)
                    return false;

                var childFrameControls = mainWindow.getAllViews();
                foreach (var childFrameControl in childFrameControls)
                {
                    if (!childFrameControl.isClosing)
                        continue;

                    var title = UIFrameworkServices.ManageViewsService.getFrameTitle(childFrameControl.hostHWnd);
                    if (string.IsNullOrEmpty(title))
                        continue;

                    if (title.Contains(view.Name))
                        return true;
                }
            }

            return false;
        }

        void application_ViewActivated(object sender, ViewActivatedEventArgs e)
        {
            var uiApplication = sender as UIApplication;
            if (uiApplication == null || uiApplication.ActiveUIDocument == null)
                return;

            var uiDocument = uiApplication.ActiveUIDocument;
            if (IsViewClosed(view, uiDocument))
            {

            }
        }

 

0 Likes
Message 4 of 7

FAIR59
Advisor
Advisor

You were on the right track using the UIFrameWork. The trick is to subscribe to the IsClosing event for newly opened views, for the startview in the DocumentOpened event, for the others in the ViewActivated event.

 

Dictionary<object,Tuple<Document, ElementId>> ContentNames = new Dictionary<object, Tuple<Document, ElementId>>();
private void M_ctrlApp_ViewActivated(object sender, Autodesk.Revit.UI.Events.ViewActivatedEventArgs e)
{
    Autodesk.Revit.DB.View active = e.CurrentActiveView;
    var mainWindow = UIFramework.MainWindow.getMainWnd();
    if (mainWindow != null)
    {
        foreach (MFCMDIChildFrameControl child in mainWindow.getAllViews())
        {
            if (!ContentNames.Keys.Contains(child))
            {
                ContentNames.Add(child,new Tuple<Document, ElementId>(e.Document, active.Id));
                child.IsClosing += Child_IsClosing;
                break;
            }
        }
    }
}
private void ControlledApplication_DocumentOpened(object sender, Autodesk.Revit.DB.Events.DocumentOpenedEventArgs e)
{
    Autodesk.Revit.DB.View active = e.Document.ActiveView;
    var mainWindow = UIFramework.MainWindow.getMainWnd();
    if (mainWindow != null)
    {
        foreach (MFCMDIChildFrameControl child in mainWindow.getAllViews())
        {
            if (!ContentNames.Keys.Contains(child)) ContentNames.Add(child,new Tuple<Document, ElementId>(e.Document, active.Id));
            child.IsClosing += Child_IsClosing;
        }
    }
}

private void Child_IsClosing(object sender, EventArgs e)
{
    MFCMDIChildFrameControl ctrl = sender as MFCMDIChildFrameControl;
    if (ContentNames.Keys.Contains(ctrl))
    {
        Tuple < Document, ElementId > info = ContentNames[ctrl];
        Autodesk.Revit.DB.View closingview = info.Item1.GetElement(info.Item2) as Autodesk.Revit.DB.View;
        TaskDialog.Show("handler", string.Format("closing view {0} {1}",closingview==null? "<none>": closingview.Name, info.Item2.ToString()));
        ContentNames.Remove(ctrl);
    }
}

 

 

Message 5 of 7

nguyenhai2499
Participant
Participant
Hello. What references to using UIFramework?
0 Likes
Message 6 of 7

Kennan.Chen
Advocate
Advocate
It is the UIFramework.dll under revit installation folder
0 Likes
Message 7 of 7

michael-coffey
Advocate
Advocate

In case anyone finds themself here (like me), I added a Revit Idea to provide a specific event for this:  https://forums.autodesk.com/t5/revit-ideas/api-viewclosed-viewclosing-events/idi-p/11598594

Please vote!