OnProjectOpen Function?

OnProjectOpen Function?

coopgodd
Contributor Contributor
962 Views
4 Replies
Message 1 of 5

OnProjectOpen Function?

coopgodd
Contributor
Contributor

Hey there,

I am currently using a WPF window and it opens when there is no project opened in Revit. That being said, to use the features of the WPF (collecting data from the floors of a project), it must be reloaded to/when a project is opened in Revit so that it actually collects the data. 

Is there a built-in function within the Revit API or a way to have this WPF Page reload when a new project is opened?

 

Thank you!

0 Likes
Accepted solutions (1)
963 Views
4 Replies
Replies (4)
Message 2 of 5

paul.nelsonCDRHK
Participant
Participant
Accepted solution

Something I found missing when I was trying to get a dockablepane WPF project up and running is how to get read/write access to the WPF interactively. The basics are, make sure the WPF is a WPF page and the class has IDockablePaneProvider as a partial class in the page.XAML.cs file. 

using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using static System.Net.Mime.MediaTypeNames;
// too many includes here
namespace BIMAppRvt
{
    /// <summary>
    /// Interaction logic for SheetGenerator.xaml
    /// </summary>
    public partial class SheetGenerator : Page, IDockablePaneProvider
    {
        private EventHandlers eventHandler;
        private ExternalEvent extEvent;
      //  public EventHandlers eventHandler;
      //  public ExternalEvent extEvent;

        public void SetupDockablePane(DockablePaneProviderData data)
        {
            data.FrameworkElement = this as FrameworkElement;
            data.InitialState = new DockablePaneState();
            data.InitialState.DockPosition = DockPosition.Right;
            data.VisibleByDefault = false;
        }

        public SheetGenerator(ExternalEvent exEvent, EventHandlers handlers)
        {
            InitializeComponent();
            eventHandler = handlers;
            extEvent = exEvent;
        }

in your main app, create class instances of the WPF page(s).

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using System.IO;
using System.Reflection;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.DB.Architecture;
using System.Windows.Controls;
using Autodesk.Revit.DB.Events;
using System.Windows.Controls.Ribbon;
using Autodesk.Revit.UI.Events;
using Autodesk.Revit.DB.Mechanical;
using System.Windows.Input;
using System.Windows;
using MessageBox = System.Windows.MessageBox;
using System.Security.Cryptography;
using System.Xml.Linq;
using ListViewItem = System.Windows.Controls.ListViewItem;
using System.Collections.Specialized;
using System.Windows.Controls.Primitives;
using Application = Autodesk.Revit.ApplicationServices.Application;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace BIMAppRvt
{
    public class BIMApp : IExternalApplication
    {
        internal static BIMApp thisApp = null;
// add a class instance of each WPF page
        public static SheetGenerator SheetGenPane { get; set; }
        public static LegendCopy LegendCopyPane { get; set; }
// classes to initialise the dockablepanes
        public static DockablePaneId SheetGenPaneId { get { return new DockablePaneId(new Guid("4B7CFCA2-8F4C-45E5-9E3E-E3E732E04659")); } }
        public static DockablePaneId LegendCopyPaneId { get { return new DockablePaneId(new Guid("3DE4A629-7774-4C9E-A6FE-FF2001C78669")); } }
        public static DataGridRow dgr { get; set; }
        public static Document cDoc = null;
//static list of all the dockablepanes
        public static List<DockablePaneId> DockPanes()
        {
            List<DockablePaneId> dPlist = new List<DockablePaneId>();
            dPlist.Clear();
            dPlist.Add(SheetGenPaneId);
            dPlist.Add(LegendCopyPaneId);
            return dPlist;
        }

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

        public Result OnStartup(UIControlledApplication application)
        {
            thisApp = this;  // static access to this application instance
            Utilities utilities = new Utilities();
// declare the event handlers to allow revit commands to be run from the pane
            EventHandlers handlers = new EventHandlers();
            ExternalEvent exEvent = ExternalEvent.Create(handlers);
// create Instances of docakble panes
            SheetGenerator sPane = new SheetGenerator(exEvent, handlers);
            LegendCopy  lPane = new LegendCopy(exEvent, handlers);
// set the dockpane classes to the instances to allow read/write to WPF //controls
//****************************************
            SheetGenPane = sPane;
            LegendCopyPane = lPane;
//******************************************
// register the dockablepanes
            application.RegisterDockablePane(SheetGenPaneId, "Sheet Generator", SheetGenPane as IDockablePaneProvider);
            application.RegisterDockablePane(LegendCopyPaneId, "Legends on Sheets", LegendCopyPane as IDockablePaneProvider);



            utilities.AddRibbonPanel(application);
            application.ControlledApplication.DocumentOpened += new EventHandler<Autodesk.Revit.DB.Events.DocumentOpenedEventArgs>(Application_DocumentOpened);
            return Result.Succeeded;
        }
// actions for when a project is opened
        private void Application_DocumentOpened(object sender, DocumentOpenedEventArgs args)
        {
            Document doc = args.Document;
            cDoc = doc;
            UIApplication UIApp = new UIApplication(doc.Application);
            Utilities utilities = new Utilities();
            try
            {
// utility that loops through the dockpane instances and closes them
                utilities.Hidepanes(UIApp);
          
            }
            catch(Exception ex) 
            {
                MessageBox.Show(ex.Message);
            }
        }

    }


}

To open the dockablepanes, call dockpane.show from the command

    public class MultiSheet : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            Document doc = commandData.Application.ActiveUIDocument.Document;
            UIApplication UIApp = new UIApplication(doc.Application);
            Utilities utils = new Utilities();
// hide all the panes again
            utils.Hidepanes(UIApp);
// get the dockable pane you want to use
            DockablePane pid = UIApp.GetDockablePane(BIMApp.SheetGenPaneId);
// initialise the WPF controls through classes and functions
            utils.MakeLegendList(UIApp, BIMApp.SheetGenPane.LegendSelectorListView);
            utils.MakeSheetList(UIApp, BIMApp.SheetGenPane.SheetTamplateSelectorListview);
            utils.MakeTitleBlockList(UIApp, BIMApp.SheetGenPane.TitleBlockSelector);
            utils.MakeSheetParameterList(UIApp);
            utils.ViewParametersList(UIApp, BIMApp.SheetGenPane.ViewFilterParameterCombo);
            utils.MakeViewList(UIApp, BIMApp.SheetGenPane.ViewSelectionList, BIMApp.SheetGenPane.ViewFilters, "Family");
            utils.MakeLevelGrid(UIApp, BIMApp.SheetGenPane.LevelSettings);
// show the correct dockable pane for the current command
            pid.Show();
            UIApp.ViewActivated += UIApp_ViewActivated;
            return Result.Succeeded;
        }
// function to handle views changing in the editor
        private void UIApp_ViewActivated(object sender, ViewActivatedEventArgs e)
        {
            UIApplication UIApp = sender as UIApplication;
            if (UIApp != null)
            {
                Utilities utils = new Utilities();
                ViewType vt = e.CurrentActiveView.ViewType;
                if (vt == ViewType.DrawingSheet)
                {
                    BIMApp.SheetGenPane.SheetParameterDataGrid.IsEnabled = true;
                    utils.MakeSheetParameterList(UIApp);
                }
                else
                {
                    BIMApp.SheetGenPane.SheetParameterDataGrid.IsEnabled = false;
                }
            }
          //  throw new NotImplementedException();
        }
    }

Here's the function for hiding the DockablePanes:-

        public void Hidepanes(UIApplication application)
        {
            List<DockablePaneId> dockablePanes = BIMApp.DockPanes();
// Loops the static list defined in the main appliction
            foreach (DockablePaneId dPID in dockablePanes)
            {
                DockablePane dpn = application.GetDockablePane(dPID);
                dpn.Hide();
            }
        }

These examples are a bit long winded but they are from an active application project with multiple dockable panes where reopening Revit is not an option. Hope this helps.

Message 3 of 5

jeremy_tammik
Alumni
Alumni

Short answer: yes, you can implement an external application and subscribe to the DocumentOpened event:

  

https://www.revitapidocs.com/2023/b9415c2d-442e-f61d-aafa-de31cce7959b.htm

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 4 of 5

coopgodd
Contributor
Contributor

Thanks for the response! This will be super helpful.

0 Likes
Message 5 of 5

coopgodd
Contributor
Contributor

Thanks for the in depth examples and everything! Much appreciated. I'll be sure to imitate parts of your code in my own, you have some great ideas.