Keep pyRevit prompt open while doing input in Revit

Hi,

is it possible to prompt a user for some input in a window, while the user is also doing stuff in Revit?

I want to make a tool that hides things in view based on what categories are selected with checkboxes in a prompt. Ideally, the user can keep the prompt open and to quickly hide/unhide categories while manipulating the view in Revit.

So far, all my prompts block out any input in Revit until the prompt is closed.

hi mve1122,

Have a look here.

I think that answers your question.

Hmm thanks, i am however unable to import dc3dServer from pyrevit.revit

you don’t really need the dc3dServer for a modeless window, those are not related. For a modeless window the following snippet is enough:

class UI(forms.WPFWindow):
    def __init__(self, xaml_file_name):
        forms.WPFWindow.__init__(self, xaml_file_name, handle_esc=False)

ui = UI("ui.xaml")
ui.show(modal=False)

If you want to have eventhandlers that do stuff on revit events then it is slightly more complicated, and will require to unsubscribe from them on closing the window

If you don’t want to block user input during your tool’s operation, a modeless window that triggers external events is the only way to go. If you just try to use a modeless window that makes regular API calls, it will almost always crash Revit. You need to trigger your API calls within an external event.

I did so in this earlier forum post where I used a XAML UI to trigger external events. (you don’t have to read through the whole thread, just find where I posted the finished code near the bottom and study up on the code related to external events.) Ehsan has also posted a good video tutorial on the pyRevit youtube channel. It’s a lot to learn, but it works very well in the end.
https://discourse.pyrevitlabs.io/t/xaml-ui-unresponsive-until-focus-is-switched-to-other-window/3162/8

This came up in the dynamo forum the other day. voltadynabim.blogspot.com posted an example and I tweaked it a bit so I could run it in Revit Python Shell. It is in IPY3, but you can look it up on the dynamo forum and see teh IPY2 comments. It’s a good working example.

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 = __revit__.uiap.ActiveUIDocument
        #_doc = __revit__.uidoc.Document
        #_app = __revit__.uiap.Application
        #_view = _doc.ActiveView
        doc = __revit__.ActiveUIDocument.Document
        uidoc = __revit__.ActiveUIDocument
        uiapp = __revit__
        app = uiapp.Application
        currview = 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"        

def GetElements():
    doc = __revit__.ActiveUIDocument.Document
    elements = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Doors).WhereElementIsNotElementType()
    return elements
# create UI
lst_elem = GetElements()
#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()
1 Like