Hi,
a Python solution using IExternalEventHandler
and a ListView in a non-modal Window(wpf)
code Python (compatible with PythonNet3 and IronPython3)
import sys
import clr
import System
from System.Collections.Generic import List, IList, Dictionary
from System import EventHandler, Uri
#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
clr.AddReference('RevitAPIUI')
import Autodesk.Revit.UI as RUI
from Autodesk.Revit.UI import *
#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)
clr.AddReference("System.Xml")
clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")
import System.Windows.Controls
from System.Windows.Controls import *
from System.IO import StringReader
from System.Xml import XmlReader
from System.Windows import LogicalTreeHelper
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application
import time
import traceback
class MainForm(Window):
string_xaml = '''
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="My WPF Window" Height="500" Width="350">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- ListView -->
<ListView x:Name="ItemsListView" Grid.Row="0" Margin="10" >
<ListView.View>
<GridView>
<GridViewColumn Header="Elements (Double Click to Zoom)" Width="300" DisplayMemberBinding="{Binding Name}"/>
</GridView>
</ListView.View>
</ListView>
<!-- Button -->
<Button x:Name="ButtonOK" Grid.Row="1" Content="OK" Margin="10" Height="30" Width="100" HorizontalAlignment="Center"/>
</Grid>
</Window>'''
def __init__(self, lst_elem):
super().__init__() # remove or comment this line with IronPython2
self.lst_elem = lst_elem
xr = XmlReader.Create(StringReader(MainForm.string_xaml))
root= XamlReader.Load(xr)
for prop_info in root.GetType().GetProperties():
if prop_info.CanWrite:
try:
setattr(self, prop_info.Name, prop_info.GetValue(root))
except Exception as ex:
print(ex, prop_info.Name) # synthax modified for all engine IronPython2, IronPython3, PythonNet3
#
self.ext_eventZoom = None
self.elem = None
self.bbx_to_Zoom = None
self.InitializeComponent()
def InitializeComponent(self):
self.ListViewElement = LogicalTreeHelper.FindLogicalNode(self, "ItemsListView")
self.ListViewElement.ItemsSource = self.lst_elem
self.ListViewElement.MouseDoubleClick += self.ListView_MouseDoubleClick
#
self.ButtonOK = LogicalTreeHelper.FindLogicalNode(self, "ButtonOK")
self.ButtonOK.Click += self.ButtonOkClick
def ListView_MouseDoubleClick(self, sender, e):
try:
self.elem = e.OriginalSource.DataContext
print(self.elem)
self.bbx_to_Zoom = self.elem.get_BoundingBox(None)
self.ext_eventZoom.Raise()
except Exception as ex:
print(traceback.format_exc())
def ButtonOkClick(self, sender, e):
try:
self.ext_eventZoom.Dispose()
self.Close()
except Exception as ex:
print(traceback.format_exc())
class ModExternalEventZoom(IExternalEventHandler):
__namespace__ = "ModExternalEventZoom_SDy8"
def __init__(self, objform):
super().__init__() # remove or comment this line with IronPython2
self.objform = objform
def Execute(self, _uiap):
_uidoc = _uiap.ActiveUIDocument
_doc = _uidoc.Document
_app = _uiap.Application
_view = _doc.ActiveView
filterFunc = lambda x : not x.IsTemplate and x.ViewType == ViewType.ThreeD and (x.Name == "{3D - " + _app.Username + "}" or x.Name == "{3D}")
threeViewD = FilteredElementCollector(_doc).OfCategory(BuiltInCategory.OST_Views).WhereElementIsNotElementType()\
.FirstOrDefault(System.Func[DB.Element, System.Boolean](filterFunc))
#processing
if self.objform.bbx_to_Zoom is not None:
pt1 = self.objform.bbx_to_Zoom.Min
pt2 = self.objform.bbx_to_Zoom.Max
tx = Transaction(_doc)
tx.Start("MyEventZoom")
try:
threeViewD.SetSectionBox(self.objform.bbx_to_Zoom)
_uidoc.Selection.SetElementIds(List[ElementId]([self.objform.elem.Id]))
except Exception as ex:
print(traceback.format_exc())
tx.Commit()
_uidoc.RequestViewChange(threeViewD)
try:
uiviews = _uidoc.GetOpenUIViews()
uiview = next((x for x in uiviews if x.ViewId == threeViewD.Id), None)
if uiview is not None:
uiview.ZoomAndCenterRectangle(pt1, pt2)
except Exception as ex:
print(traceback.format_exc())
def GetName(self):
return "ModExternalEventZoom"
# create UI
lst_elem = UnwrapElement(IN[0])
TransactionManager.Instance.ForceCloseTransaction()
winObj = MainForm(lst_elem)
obj_handlerZoom = ModExternalEventZoom(winObj)
ext_eventZoom = ExternalEvent.Create(obj_handlerZoom)
# set attribute event
winObj.ext_eventZoom = ext_eventZoom
winObj.Show()
It will need to be adapted if
-you use ElementIds as input instead of Elements
-you use IronPython2 (I advise against using CPython3 for this example)
use AI for code comprehension if necessary