Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Modeless Form example

9 REPLIES 9
SOLVED
Reply
Message 1 of 10
sobon.konrad
4243 Views, 9 Replies

Modeless Form example

So i was looking at Jeremy's sample post about modeless forms and was trying to modify one of the examples to do something other than flip the door. Here's my attempt and an issue it generated. 

 

For some reason when I try to execute the DeleteViews() method which should be triggered by RequestId.TurnIn what happens is that both of the functions defined below get executed: DeleteSheets and DeleteViews. 

 

Is there a way to assign separate function calls to each button? 

 

Thanks! 

 

//
// (C) Copyright 2003-2015 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Collections.Generic;

using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System.Linq;

namespace Revit.SDK.Samples.ModelessForm_ExternalEvent.CS
{
    /// <summary>
    ///   A class with methods to execute requests made by the dialog user.
    /// </summary>
    /// 
    public class RequestHandler : IExternalEventHandler
    {
        // A trivial delegate, but handy
        private delegate void DoorOperation(FamilyInstance e);

        // The value of the latest request made by the modeless form 
        private Request m_request = new Request();

        /// <summary>
        /// A public property to access the current request value
        /// </summary>
        public Request Request
        {
            get { return m_request; }
        }

        /// <summary>
        ///   A method to identify this External Event Handler
        /// </summary>
        public String GetName()
        {
            return "R2014 External Event Sample";
        }


        /// <summary>
        ///   The top method of the event handler.
        /// </summary>
        /// <remarks>
        ///   This is called by Revit after the corresponding
        ///   external event was raised (by the modeless form)
        ///   and Revit reached the time at which it could call
        ///   the event's handler (i.e. this object)
        /// </remarks>
        /// 
        public void Execute(UIApplication uiapp)
        {
            try
            {
                switch (Request.Take())
                {
                    case RequestId.None:
                        {
                            return;  // no request at this time -> we can leave immediately
                        }
                    case RequestId.Delete:
                        {
                            DeleteSheets(uiapp, "Delete sheets");
                            //ModifySelectedDoors(uiapp, "Delete sheets", e => e.Document.Delete(e.Id));
                            break;
                        }
                    //case RequestId.FlipLeftRight:
                    //    {
                    //        ModifySelectedDoors(uiapp, "Flip door Hand", e => e.flipHand());
                    //        break;
                    //    }
                    //case RequestId.FlipInOut:
                    //    {
                    //        ModifySelectedDoors(uiapp, "Flip door Facing", e => e.flipFacing());
                    //        break;
                    //    }
                    //case RequestId.MakeLeft:
                    //    {
                    //        ModifySelectedDoors(uiapp, "Make door Left", MakeLeft);
                    //        break;
                    //    }
                    //case RequestId.MakeRight:
                    //    {
                    //        ModifySelectedDoors(uiapp, "Make door Right", MakeRight);
                    //        break;
                    //    }
                    //case RequestId.TurnOut:
                    //    {
                    //        ModifySelectedDoors(uiapp, "Place door Out", TurnOut);
                    //        break;
                    //    }
                    case RequestId.TurnIn:
                        {
                            DeleteViews(uiapp, "Place door In");
                            break;
                        }
                    //case RequestId.Rotate:
                    //    {
                    //        ModifySelectedDoors(uiapp, "Rotate door", FlipHandAndFace);
                    //        break;
                    //    }
                    default:
                        {
                            // some kind of a warning here should
                            // notify us about an unexpected request 
                            break;
                        }
                }
            }
            finally
            {
                Application.thisApp.WakeFormUp();
            }

            return;
        }


        /// <summary>
        ///   The main door-modification subroutine - called from every request 
        /// </summary>
        /// <remarks>
        ///   It searches the current selection for all doors
        ///   and if it finds any it applies the requested operation to them
        /// </remarks>
        /// <param name="uiapp">The Revit application object</param>
        /// <param name="text">Caption of the transaction for the operation.</param>
        /// 
        private void DeleteSheets(UIApplication uiapp, String text)
        {
            UIDocument uidoc = uiapp.ActiveUIDocument;

            if (uidoc != null)
            {
                ICollection<ElementId> allSheets = new FilteredElementCollector(uidoc.Document)
                    .OfClass(typeof(ViewSheet))
                    .ToElementIds();

                using (Transaction trans = new Transaction(uidoc.Document))
                {
                    if (trans.Start(text) == TransactionStatus.Started)
                    {
                        foreach (ElementId id in allSheets)
                        {
                            uidoc.Document.Delete(id);
                        }
                        trans.Commit();
                    }
                }
            }
        }

        private void DeleteViews(UIApplication uiapp, String text)
        {
            UIDocument uidoc = uiapp.ActiveUIDocument;

            if (uidoc != null)
            {
                using (Transaction trans = new Transaction(uidoc.Document))
                {
                    if (trans.Start(text) == TransactionStatus.Started)
                    {
                        try
                        {
                            View currentView = uidoc.ActiveView;
                            List<ElementId> exclude = new List<ElementId>();
                            exclude.Add(currentView.Id);
                            ExclusionFilter filter = new ExclusionFilter(exclude);

                            IList<Element> collection = new FilteredElementCollector(uidoc.Document).OfClass(typeof(View)).WherePasses(filter).ToElements();

                            for (var i = 0; i < collection.Count; i++)
                            {
                                View v = collection[i] as View;
                                if (v.Name == "Project View")
                                {
                                    collection.RemoveAt(i);
                                }
                            }
                            int x = 0;
                            foreach (Element e in collection)
                            {
                                try
                                {
                                    View view = e as View;

                                    // all views/sheets are deleted and increment counter by 1
                                    uidoc.Document.Delete(view.Id);
                                    x += 1;
                                }
                                catch (Exception ex)
                                {
                                    TaskDialog.Show("Error", ex.Message);
                                }
                            }
                            trans.Commit();
                            TaskDialog.Show("DeleteAllSheetsViews", "Views & Sheets Deleted: " + x.ToString());
                        }
                        catch (Exception ex)
                        {
                            TaskDialog.Show("Error", ex.Message);
                        }
                        
                    }
                }
            }
        }


        //////////////////////////////////////////////////////////////////////////
        //
        // Helpers - simple delegates operating upon an instance of a door

        private void FlipHandAndFace(FamilyInstance e)
        {
            e.flipFacing(); e.flipHand();
        }

        // Note: The door orientation [left/right] is according the common
        // conventions used by the building industry in the Czech Republic.
        // If the convention is different in your county (like in the U.S),
        // swap the code of the MakeRight and MakeLeft methods.

        private static void MakeLeft(FamilyInstance e)
        {
            if (e.FacingFlipped ^ e.HandFlipped) e.flipHand();
        }

        private void MakeRight(FamilyInstance e)
        {
            if (!(e.FacingFlipped ^ e.HandFlipped)) e.flipHand();
        }

        // Note: The In|Out orientation depends on the position of the
        // wall the door is in; therefore it does not necessary indicates
        // the door is facing Inside, or Outside, respectively.
        // The presented implementation is good enough to demonstrate
        // how to flip a door, but the actual algorithm will likely
        // have to be changes in a read-world application.

        private void TurnIn(FamilyInstance e)
        {
            if (!e.FacingFlipped) e.flipFacing();
        }

        private void TurnOut(FamilyInstance e)
        {
            if (e.FacingFlipped) e.flipFacing();
        }

    }  // class

}  // namespace
Tags (2)
9 REPLIES 9
Message 2 of 10
arnostlobel
in reply to: sobon.konrad

The sample is actually included in the SDK.

 

I am afraid you missed an important part of the code. At the event of pressing a button in the dialog, the Id of the request is set. One specific Id per each executable button. Thus I suppose you did not set the request Id correctly there either for your Delete button or the TurnIn button.

Arnošt Löbel
Message 3 of 10
sobon.konrad
in reply to: arnostlobel

I left the settings of the form and Id setting as it was. When you hit Delete Button it will set the id to Delete just like it was. I am trying to change the actual method that this call executes by changing its name to DeleteSheets and then defning a new method called DeleteSheets. 

Issue is that when I hit Delete Button it tries to execute BOTH of the methods defined: DeleteSheets and DeleteViews. 

 

How would I tie a different method to each button? 

 

Thank you,

Message 4 of 10
arnostlobel
in reply to: sobon.konrad

Konrad,

 

did you debug it? Put a break point to both the Delete and TurnIn case block and see what makes the calls when the breakpoints are hit.

Arnošt Löbel
Message 5 of 10
sobon.konrad
in reply to: arnostlobel

This is what i get when i hit the FlipIn button:

 

Capture.PNG

 

Request that comes through is # 7 so its correct:

 

Capture.PNG

 

It then expectedly jumps to case RequestId.TurnIn: where DeleteViews (uiapp, "") should be executed:

 

Capture.PNG

 

so far everything as expected: 

 

Then exceptiosn start coming in: 

 

Capture.PNG

 

But then all my Sheets and Views are gone as if both methods were executed: 

 

Capture.PNG

 

Thank you,

 

Message 6 of 10
arnostlobel
in reply to: sobon.konrad

So, it looks like we can establish that assigning the request Id and switching on it when the event is later raised works correctly. That leads me to believe that there is probably something wrong with the DeleteSheets method or the code that executed after the method finishes, during which an exception is (presumably) thrown and probably causes havoc in the call-stack. On first look I do not see anything suspicious there, but debugging should relieve what the problem is. It could be that if the active view is actually a sheet, then I could see how Revit would get into a problem.

The exception you are getting is thrown by Revit when an API application attempts to invoke a method on an element (or document) that no longer exists (meaning: it does not have its native counterpart in Revit anymore.)

Arno?t
Arnošt Löbel
Message 7 of 10
sobon.konrad
in reply to: arnostlobel

//
// (C) Copyright 2003-2015 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Collections.Generic;

using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System.Linq;

namespace Revit.SDK.Samples.ModelessForm_ExternalEvent.CS
{
    /// <summary>
    ///   A class with methods to execute requests made by the dialog user.
    /// </summary>
    /// 
    public class RequestHandler : IExternalEventHandler
    {
        // A trivial delegate, but handy
        private delegate void DoorOperation(FamilyInstance e);

        // The value of the latest request made by the modeless form 
        private Request m_request = new Request();

        /// <summary>
        /// A public property to access the current request value
        /// </summary>
        public Request Request
        {
            get { return m_request; }
        }

        /// <summary>
        ///   A method to identify this External Event Handler
        /// </summary>
        public String GetName()
        {
            return "R2014 External Event Sample";
        }


        /// <summary>
        ///   The top method of the event handler.
        /// </summary>
        /// <remarks>
        ///   This is called by Revit after the corresponding
        ///   external event was raised (by the modeless form)
        ///   and Revit reached the time at which it could call
        ///   the event's handler (i.e. this object)
        /// </remarks>
        /// 
        public void Execute(UIApplication uiapp)
        {
            try
            {
                switch (Request.Take())
                {
                    case RequestId.None:
                        {
                            return;  // no request at this time -> we can leave immediately
                        }
                    case RequestId.Delete:
                        {
                            DeleteSheets(uiapp, "Delete sheets");
                            //ModifySelectedDoors(uiapp, "Delete sheets", e => e.Document.Delete(e.Id));
                            break;
                        }
                    //case RequestId.FlipLeftRight:
                    //    {
                    //        ModifySelectedDoors(uiapp, "Flip door Hand", e => e.flipHand());
                    //        break;
                    //    }
                    //case RequestId.FlipInOut:
                    //    {
                    //        ModifySelectedDoors(uiapp, "Flip door Facing", e => e.flipFacing());
                    //        break;
                    //    }
                    //case RequestId.MakeLeft:
                    //    {
                    //        ModifySelectedDoors(uiapp, "Make door Left", MakeLeft);
                    //        break;
                    //    }
                    //case RequestId.MakeRight:
                    //    {
                    //        ModifySelectedDoors(uiapp, "Make door Right", MakeRight);
                    //        break;
                    //    }
                    //case RequestId.TurnOut:
                    //    {
                    //        ModifySelectedDoors(uiapp, "Place door Out", TurnOut);
                    //        break;
                    //    }
                    case RequestId.TurnIn:
                        {
                            DeleteViews(uiapp, "Place door In");
                            break;
                        }
                    //case RequestId.Rotate:
                    //    {
                    //        ModifySelectedDoors(uiapp, "Rotate door", FlipHandAndFace);
                    //        break;
                    //    }
                    default:
                        {
                            // some kind of a warning here should
                            // notify us about an unexpected request 
                            break;
                        }
                }
            }
            finally
            {
                Application.thisApp.WakeFormUp();
            }

            return;
        }


        /// <summary>
        ///   The main door-modification subroutine - called from every request 
        /// </summary>
        /// <remarks>
        ///   It searches the current selection for all doors
        ///   and if it finds any it applies the requested operation to them
        /// </remarks>
        /// <param name="uiapp">The Revit application object</param>
        /// <param name="text">Caption of the transaction for the operation.</param>
        /// 
        private void DeleteSheets(UIApplication uiapp, String text)
        {
            UIDocument uidoc = uiapp.ActiveUIDocument;

            if (uidoc != null)
            {
                ICollection<ElementId> allSheets = new FilteredElementCollector(uidoc.Document)
                    .OfClass(typeof(ViewSheet))
                    .ToElementIds();

                using (Transaction trans = new Transaction(uidoc.Document))
                {
                    if (trans.Start(text) == TransactionStatus.Started)
                    {
                        foreach (ElementId id in allSheets)
                        {
                            uidoc.Document.Delete(id);
                        }
                        trans.Commit();
                    }
                }
            }
        }
        /// <summary>
        ///   The main door-modification subroutine - called from every request 
        /// </summary>
        /// <remarks>
        ///   It searches the current selection for all doors
        ///   and if it finds any it applies the requested operation to them
        /// </remarks>
        /// <param name="uiapp">The Revit application object</param>
        /// <param name="text">Caption of the transaction for the operation.</param>
        private void DeleteViews(UIApplication uiapp, String text)
        {
            UIDocument uidoc = uiapp.ActiveUIDocument;

            if (uidoc != null)
            {
                using (Transaction trans = new Transaction(uidoc.Document))
                {
                    if (trans.Start(text) == TransactionStatus.Started)
                    {
                        // create a new drafting view that will be excluded from selection
                        // and will not be deleted. cannot delete all views from project
                        ViewFamilyType viewFamilyType = new FilteredElementCollector(uidoc.Document)
                            .OfClass(typeof(ViewFamilyType))
                            .Cast<ViewFamilyType>().First(vft => vft.ViewFamily == ViewFamily.Drafting);

                        ViewDrafting view = ViewDrafting.Create(uidoc.Document, viewFamilyType.Id);
                        view.ViewName = "TempDraftingView";
                        trans.Commit();
                        uidoc.ActiveView = view;
                    }
                }
                using (Transaction trans2 = new Transaction(uidoc.Document))
                {
                    if (trans2.Start(text) == TransactionStatus.Started)
                    {
                        
                        IList<Element> allViewsTemp = new FilteredElementCollector(uidoc.Document)
                        .OfClass(typeof(View))
                        .ToElements();

                        List<ElementId> exclude = new List<ElementId>();
                        foreach (Element e in allViewsTemp)
                        {
                            View view = e as View;
                            if (view.Name == "TempDraftingView")
                            {
                                exclude.Add(view.Id);
                            }
                        }
                        //exclude.Add(uidoc.ActiveView.Id);
                        ExclusionFilter filter = new ExclusionFilter(exclude);
                        IList<Element> allViews = new FilteredElementCollector(uidoc.Document)
                            .OfClass(typeof(View))
                            .WherePasses(filter)
                            .ToElements();

                        // Remove all ViewTemplates, sheets, project browser and
                        // system browser from views to be deleted
                        List<View> viewsToDelete = new List<View>();

                        foreach (Element e in allViews)
                        {
                            View v = e as View;
                            if (!v.IsTemplate 
                                && !(v.ViewType == ViewType.SystemBrowser) 
                                && !(v.ViewType == ViewType.DrawingSheet) 
                                && !(v.ViewType == ViewType.ProjectBrowser))
                            {
                                viewsToDelete.Add(v);
                            }
                        }

                        foreach (View v in viewsToDelete)
                        {
                            try
                            {
                                if (v.IsValidObject)
                                {
                                    uidoc.Document.Delete(v.Id);
                                } 
                            }
                            catch (Exception ex)
                            {
                                TaskDialog.Show("Error", ex.Message + v.Id);
                            }
                        }
                        trans2.Commit();
                    }
                }
            }
        }


        //////////////////////////////////////////////////////////////////////////
        //
        // Helpers - simple delegates operating upon an instance of a door

        private void FlipHandAndFace(FamilyInstance e)
        {
            e.flipFacing(); e.flipHand();
        }

        // Note: The door orientation [left/right] is according the common
        // conventions used by the building industry in the Czech Republic.
        // If the convention is different in your county (like in the U.S),
        // swap the code of the MakeRight and MakeLeft methods.

        private static void MakeLeft(FamilyInstance e)
        {
            if (e.FacingFlipped ^ e.HandFlipped) e.flipHand();
        }

        private void MakeRight(FamilyInstance e)
        {
            if (!(e.FacingFlipped ^ e.HandFlipped)) e.flipHand();
        }

        // Note: The In|Out orientation depends on the position of the
        // wall the door is in; therefore it does not necessary indicates
        // the door is facing Inside, or Outside, respectively.
        // The presented implementation is good enough to demonstrate
        // how to flip a door, but the actual algorithm will likely
        // have to be changes in a read-world application.

        private void TurnIn(FamilyInstance e)
        {
            if (!e.FacingFlipped) e.flipFacing();
        }

        private void TurnOut(FamilyInstance e)
        {
            if (e.FacingFlipped) e.flipFacing();
        }

    }  // class

}  // namespace

It seems like for some reason I kept getting InvalidObjects into my selection and thus causing exceptions when tried to delete them. I have no idea how that is possible, but I was able to go around this by adding an "if" statement that checks for whether an object is valid right before trying to delete it.

 

During this process I also realized that SystemBrowser and ProjectBrowser are now a legit ViewTypes and are being returned with all views. Of course Templates have been part of that for a while now, so I also added checks to exclude all of the above from deletion list. 

 

Also I added a quick routine to create a new Drafting view, set that to current view and exclude it from deletion. That's to prevent an error that would arise if all views were deleted from the project.


It seems to be working now. At least I am getting the results that I was expecting. 


The next question is how to, instead of hitting Button1 to delete all views and Button2 to delete all sheets, set this up so i can have couple check boxes and then execute one command at the end that will either delete all views, all sheets or both sheets and views. 

Can you give me some tips about that? I am guessing I should use some global variable that will be set when checkbox is checked and then when command is executed check what those variables are set to and execute the appropriate command. Any examples that I can look at? 

 

Thanks! 

Message 8 of 10
arnostlobel
in reply to: sobon.konrad

Sorry, I cannot give you tips about that. It's programming 101 - you need to go back to the books.

Cheers

Arnošt Löbel
Message 9 of 10
sobon.konrad
in reply to: arnostlobel

Hahahaha, fair enough. 

 

PS. I never studied Computer Science so sometimes those 101 tasks can be a little challanging. Anyways, thanks for help. 

Message 10 of 10
arnostlobel
in reply to: sobon.konrad

I never studied Computer Science either. I have just worked my way through it. Yuu'll get there too, no doubt.

Arnošt Löbel

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Forma Design Contest


Rail Community