Python Dispatcher Threads

Just having some fun trying to get the current dispatcher thread in Sandbox to use with WPF… (eventually I would like to get it running in Revit, but that also crashes, hoping get this working will inform that)

Currently all attempts are crashing!

All thoughts welcome, I am way out of my depth :smiley:

Thanks to @Michael_Kirschner2 for assistance so far.

Cheers,

Mark

# Reference the WPF assemblies
import clr
import sys
import System.Windows
from wpf import *
from System.Threading import Thread, ThreadStart, ApartmentState
clr.AddReference('PresentationFramework')

# Initialization Constants
Window = System.Windows.Window
Application = System.Windows.Application
app = Application()
appD = Application.Current.Dispatcher
#Dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;

def appThread():
    # Create window
    my_window = Window()
    # Run application
    my_app = appD
    my_app.Run (my_window)
    
thread = Thread(ThreadStart(appThread))
#thread.SetApartmentState(ApartmentState.STA)
thread.Start()
thread.Join()
1 Like

So thanks to Michael, I have got this running in Sandbox…

# Reference the WPF assemblies
import clr
import sys
import System.Windows
from wpf import *
from System.Threading import Thread, ThreadStart, ApartmentState
clr.AddReference('PresentationFramework')

# Initialization Constants
Window = System.Windows.Window
Application = System.Windows.Application

def appThread():
    my_window = Window()
    my_window.Show()
    
thread = Application.Current.Dispatcher.Invoke(appThread)

However in DynamoRevit, it is still chucking an error (presumably due to Revit having 1 thread not a separate dispatch thread.

I found an interesting thing here… https://pythoncvc.net/?p=247 and doctored it to get it running in Dynamo Revit :slight_smile:

import clr

# Reference the WPF assemblies
import sys
import System.Windows
from wpf import *
clr.AddReference('PresentationFramework')
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
clr.AddReference('RevitServices')
# noinspection PyUnresolvedReferences
from Autodesk.Revit.UI import IExternalEventHandler, ExternalEvent
# noinspection PyUnresolvedReferences
from Autodesk.Revit.DB import Transaction
# noinspection PyUnresolvedReferences
from Autodesk.Revit.Exceptions import InvalidOperationException

from RevitServices import *
from RevitServices.Persistence import DocumentManager
from Autodesk.Revit.UI import *
from Autodesk.Revit.UI.Selection import *
doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
# Initialization Constants
Window = System.Windows.Window

# Simple function we want to run
def delete_elements():
    t = Transaction(doc, "Failing script")
    t.Start()
    for elid in uidoc.Selection.GetElementIds():
        print elid
        doc.Delete(elid)
    t.Commit()
    
# Create a subclass of IExternalEventHandler
class SimpleEventHandler(IExternalEventHandler):
    """
    Simple IExternalEventHandler sample
    """
    # __init__ is used to make function from outside of the class to be executed by the handler. \
    # Instructions could be simply written under Execute method only
    def __init__(self, do_this):
        self.do_this = do_this
    # Execute method run in Revit API environment.
    def Execute(self, uiapp):
        try:
            self.do_this()
        except InvalidOperationException:
            # If you don't catch this exeption Revit may crash.
            print "InvalidOperationException catched"
    def GetName(self):
        return "simple function executed by an IExternalEventHandler in a Form"
# Now we need to make an instance of this handler. Moreover, it shows that the same class could be used to for
# different functions using different handler class instances
simple_event_handler = SimpleEventHandler(delete_elements)
# We now need to create the ExternalEvent
ext_event = ExternalEvent.Create(simple_event_handler)

# A simple WPF form used to call the ExternalEvent
class ModelessForm(Window):#WPFWindow):
    """
    Simple modeless form sample#
    """
    def __init__(self):
        Window.__init__(self)
        self.Title = "Hello World"
        self.Show()
    def delete_click(self, sender, e):
        # This Raise() method launch a signal to Revit to tell him you want to do something in the API context
        ext_event.Raise()
# Let's launch our beautiful and useful form !
modeless_form = ModelessForm()
4 Likes