diff --git a/docs/pages/_en/1.0/reference/release-notes.md b/docs/pages/_en/1.0/reference/release-notes.md
index 2e1943591..92e52624a 100644
--- a/docs/pages/_en/1.0/reference/release-notes.md
+++ b/docs/pages/_en/1.0/reference/release-notes.md
@@ -15,6 +15,8 @@ group: Deployment & Configs
### RC
+- Added 'Open View' component.
+
{% endcapture %}
{% include ltr/release_header_next.html title="Upcoming Changes" note=rc_release_notes %}
diff --git a/src/RhinoInside.Revit.External/DB/Extensions/Document.cs b/src/RhinoInside.Revit.External/DB/Extensions/Document.cs
index 8b48eea27..33eeadf8e 100644
--- a/src/RhinoInside.Revit.External/DB/Extensions/Document.cs
+++ b/src/RhinoInside.Revit.External/DB/Extensions/Document.cs
@@ -998,12 +998,17 @@ public static View GetActiveGraphicalView(this Document doc)
}
///
- /// Sets the active Graphical of the provided .
+ /// Sets the active of the provided .
///
///
/// View to be activated
- public static bool SetActiveGraphicalView(this Document document, View view) =>
- SetActiveGraphicalView(document, view, out var _);
+ public static bool SetActiveView(this Document document, View view)
+ {
+ if (view is null)
+ throw new ArgumentNullException(nameof(view));
+
+ return SetActiveView(document, view, out var _);
+ }
///
/// Sets the active Graphical of the provided .
@@ -1018,6 +1023,16 @@ public static bool SetActiveGraphicalView(this Document document, View view, out
if (!view.IsGraphicalView())
throw new ArgumentException("Input view is not a graphical view.", nameof(view));
+ return SetActiveView(document, view, out wasOpened);
+ }
+
+ ///
+ /// Sets the active Graphical of the provided .
+ ///
+ ///
+ /// View to be activated
+ private static bool SetActiveView(this Document document, View view, out bool wasOpened)
+ {
if (!document.Equals(view.Document))
throw new ArgumentException("View does not belong to the specified document", nameof(view));
diff --git a/src/RhinoInside.Revit.External/UI/UIHostApplicationUnconstrained.cs b/src/RhinoInside.Revit.External/UI/UIHostApplicationUnconstrained.cs
index 1b78d9e0d..ace0a197e 100644
--- a/src/RhinoInside.Revit.External/UI/UIHostApplicationUnconstrained.cs
+++ b/src/RhinoInside.Revit.External/UI/UIHostApplicationUnconstrained.cs
@@ -46,7 +46,7 @@ public override UIDocument ActiveUIDocument
if (value.TryGetActiveGraphicalView(out var uiView))
{
HostedApplication.Active.InvokeInHostContext
- (() => value.Document.SetActiveGraphicalView(value.Document.GetElement(uiView.ViewId) as View));
+ (() => value.Document.SetActiveGraphicalView(value.Document.GetElement(uiView.ViewId) as View, out var _));
}
}
}
diff --git a/src/RhinoInside.Revit.GH/Components/Groups/AddDetailGroup.cs b/src/RhinoInside.Revit.GH/Components/Groups/AddDetailGroup.cs
index 62f3d80de..19afee910 100644
--- a/src/RhinoInside.Revit.GH/Components/Groups/AddDetailGroup.cs
+++ b/src/RhinoInside.Revit.GH/Components/Groups/AddDetailGroup.cs
@@ -111,7 +111,7 @@ protected override void AfterSolveInstance()
{
base.AfterSolveInstance();
- ActiveView?.Document.SetActiveGraphicalView(ActiveView);
+ ActiveView?.Document.SetActiveView(ActiveView);
ActiveView = default;
if (ViewsToClose.Count > 0)
diff --git a/src/RhinoInside.Revit.GH/Components/Topology/AddSpace.cs b/src/RhinoInside.Revit.GH/Components/Topology/AddSpace.cs
index 1daaa42b4..108a3db28 100644
--- a/src/RhinoInside.Revit.GH/Components/Topology/AddSpace.cs
+++ b/src/RhinoInside.Revit.GH/Components/Topology/AddSpace.cs
@@ -145,7 +145,7 @@ protected override void AfterSolveInstance()
{
base.AfterSolveInstance();
- ActiveView?.Document.SetActiveGraphicalView(ActiveView);
+ ActiveView?.Document.SetActiveView(ActiveView);
ActiveView = default;
foreach (var view in (ViewsToClose as IEnumerable).Reverse())
diff --git a/src/RhinoInside.Revit.GH/Components/Views/Open.cs b/src/RhinoInside.Revit.GH/Components/Views/Open.cs
new file mode 100644
index 000000000..2a81f3c10
--- /dev/null
+++ b/src/RhinoInside.Revit.GH/Components/Views/Open.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Forms;
+using Grasshopper.Kernel;
+using Grasshopper.Kernel.Data;
+using Grasshopper.Kernel.Parameters;
+using Grasshopper.Kernel.Types;
+using RhinoInside.Revit.External.DB.Extensions;
+using ARDB = Autodesk.Revit.DB;
+using ARUI = Autodesk.Revit.UI;
+
+namespace RhinoInside.Revit.GH.Components.Views
+{
+ [ComponentVersion(introduced: "1.18")]
+ public class ViewOpen : ZuiComponent
+ {
+ public override Guid ComponentGuid => new Guid("E13FC388-D607-4A62-BEBC-498A9445F91A");
+ public override GH_Exposure Exposure => GH_Exposure.primary;
+ protected override string IconTag => string.Empty;
+
+ public ViewOpen() : base
+ (
+ name: "Open View",
+ nickname: "V-Open",
+ description: "Open-Close a Revit view",
+ category: "Revit",
+ subCategory: "View"
+ )
+ { }
+
+ protected override ParamDefinition[] Inputs => inputs;
+ static readonly ParamDefinition[] inputs =
+ {
+ ParamDefinition.Create("View", "V", string.Empty),
+ ParamDefinition.Create("Open", "O", string.Empty, optional: true, relevance: ParamRelevance.Primary)
+ };
+
+ protected override ParamDefinition[] Outputs => outputs;
+ static readonly ParamDefinition[] outputs =
+ {
+ ParamDefinition.Create("View", "V", string.Empty),
+ ParamDefinition.Create("Open", "O", string.Empty, optional: true, relevance: ParamRelevance.Primary)
+ };
+
+ private readonly Dictionary ViewStates = new Dictionary();
+ protected override void BeforeSolveInstance()
+ {
+ base.BeforeSolveInstance();
+ }
+
+ protected override void TrySolveInstance(IGH_DataAccess DA)
+ {
+ if (!Params.TryGetData(DA, "View", out Types.View view, x => x.IsValid)) return;
+ else Params.TrySetData(DA, "View", () => view);
+ if (!Params.TryGetData(DA, "Open", out bool? open)) return;
+
+ var isOpen = view.Value.IsOpen();
+ if (open is object)
+ {
+ if (view.Value.IsTemplate && open is true)
+ AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"Can't open view template '{view.DisplayName}'");
+ else if (view.Value.IsCallout && open is true)
+ AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"Can't open callout view'{view.DisplayName}'");
+ else
+ ViewStates[view] = open.Value;
+ }
+
+ Params.TrySetData(DA, "Open", () => isOpen);
+ }
+
+ protected override void AfterSolveInstance()
+ {
+ if (ViewStates.Count > 0)
+ {
+ try
+ {
+ Guest.Instance.CommitTransactionGroups();
+ var activeView = Revit.ActiveUIDocument.ActiveView;
+
+ try
+ {
+ foreach (var group in ViewStates.GroupBy(x => x.Key.Document))
+ {
+ using (var uiDocument = new ARUI.UIDocument(group.Key))
+ {
+ var openViews = uiDocument.GetOpenUIViews();
+ if (openViews.Count == 0)
+ {
+ AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"Document {uiDocument.Document.GetTitle()} is not open on UI.");
+ }
+ else
+ {
+ var openViewIds = new HashSet(openViews.Select(x => x.ViewId));
+ var viewsToClose = group.Where(x => x.Value == false).Select(x => x.Key);
+ var viewsToOpen = group.Where(x => x.Value == true).Select(x => x.Key);
+
+ foreach (var view in viewsToOpen)
+ {
+ if (!openViewIds.Contains(view.Id))
+ view.Value.Document.SetActiveView(view.Value);
+ }
+
+ foreach (var view in viewsToClose)
+ {
+ if (view.Value.IsEquivalent(activeView))
+ {
+ AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"Can't close '{view.DisplayName}' because is the active one.");
+ }
+ else
+ {
+ try { view.Value.Close(); }
+ catch (Exception e) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message); }
+ }
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ activeView.Document.SetActiveView(activeView);
+ }
+
+ // Reconstruct output 'Open' with final values from 'View'.
+ var _View_ = Params.IndexOfOutputParam("View");
+ var _Open_ = Params.IndexOfOutputParam("Open");
+ if (_View_ >= 0 && _Open_ >= 0)
+ {
+ var viewParam = Params.Output[_View_];
+ var openParam = Params.Output[_Open_];
+ var openData = new GH_Structure();
+
+ var viewData = viewParam.VolatileData;
+ foreach (var path in viewData.Paths)
+ {
+ var open = viewData.get_Branch(path).Cast