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.