🚨 Custom WPF Forms Issue in pyRevit // Revit 2024

:memo: Issue Description

When using custom WPF forms in PyRevit scripts, there appears to be a dependency on having at least one PyRevit DialogTask window open in Revit 2024. Without an open DialogTask, the custom WPF forms either don’t appear or cause the application to freeze.

:wrench: Environment Details

  • Revit Versions Tested:
    • Revit 2024.3 (:x: Issue present)
    • Revit 2025.4 (:white_check_mark: Working correctly)
  • PyRevit Versions Tested:
    • 5.0.0.24354
    • 5.0.0.24315

:mag: Behavior

  1. In Revit 2024.3:

    • :x: First execution of a script with custom WPF forms fails unless a PyRevit DialogTask is already open
    • :warning: Subsequent executions may cause the UI to freeze
    • :arrows_counterclockwise: The script works properly only when at least one PyRevit dialog (e.g., a search dialog or any other PyRevit window) is open
    • :zap: The issue persists even with proper form cleanup and disposal
  2. In Revit 2025.4:

    • :white_check_mark: All functionality works as expected
    • :dart: No dependency on having PyRevit dialogs open
    • :dizzy: Custom WPF forms display and close properly

:hammer_and_wrench: Attempted Solutions

  • :recycle: Implemented proper form cleanup and disposal
  • :arrows_counterclockwise: Added Windows Forms message pump handling
  • :link: Ensured proper UI thread synchronization
  • :broom: Added explicit disposal of dialog resources

:computer: Code Examples

Example 1: Complex UI with Multiple Components

The issue occurs with custom WPF forms created using custom dp_forms:

from dp_forms import dp_MainUI, dp__AlertMessage

def show_dialog(dialog):
    """Show dialog with proper cleanup."""
    try:
        if hasattr(dialog, 'show'):
            dialog.show()
        else:
            dialog.ShowDialog()
    finally:
        if hasattr(dialog, 'Dispose'):
            dialog.Dispose()
        WinFormsApp.DoEvents()

# Example usage
ui = dp_MainUI(
    title="Window Title",
    components=[...],
    show_cancel=True
)
show_dialog(ui)

Example 2: Simple Alert Message

Even simple alert messages are affected:

from dp_forms import dp__AlertMessage

# Simple alert message that won't show up without a PyRevit dialog open
alert = dp__AlertMessage(
    msg="Error:",
    sub_msg="No valid beam types found.",
    title="Error"
)
alert.ShowDialog()  # This will fail unless a PyRevit dialog is already open

:boom: Impact

This issue affects any PyRevit script that uses custom WPF forms in Revit 2024, requiring users to have a PyRevit dialog open before executing scripts with custom forms. This creates an unintuitive and potentially confusing user experience.

:question: Questions

  1. Is this a known issue with WPF handling in PyRevit for Revit 2024?
  2. Are there any workarounds besides having a PyRevit dialog open?
  3. Could this be related to changes in how Revit 2024 handles WPF windows compared to Revit 2025?

:pushpin: Additional Notes

  • :dart: The issue seems specific to custom WPF forms and doesn’t affect native PyRevit forms
  • :arrows_counterclockwise: The behavior is consistent across different PyRevit versions tested
  • :bulb: The problem appears to be related to the WPF window handling mechanism in Revit 2024

Hi @dp_tools, thanks for the detailed report!

Unfortunately, you have left out the most important thing: what’s the code inside dp__AlertMessage? Without it, we cannot even try to reproduce your problem and find its cause.

Does this code work with pyrevit 4.8?

Can you try to run the command in debug mode (CTRL+CLick on the button) and see if there’s something useful in the output window?

BTW: do you know that there is already a pyrevit.forms.alert function, so you can directly use that?

BTW2: “DialogTask” is not a term used anywhere in the pyRevit, Revit, or even Windows environment; there’s the concept of “Task Dialog”, but what you meant is any kind of UI opened by pyRevit.
I had an hard time to understand what you were talking about :sweat_smile:

Also, you say it is a WPF form, but your show_dialog function calls DoEvents which is a Windows Forms thing. You shouldn’t mix the two frameworks, they are really different things!

Hi @sanzoghenzo :grin:,

Thanks for your reply!

Below is the code we created during Lesson 0302 in the WPF course by @ErikFrits . As mentioned, the message dialog appears only on the first run. On subsequent interactions, Revit freezes. Occasionally, I also experience an empty Revit UI, which seems to occur across many scripts.

However, if the “Task Dialog” opens successfully on the first attempt, it often works without further issues.

This issue persists even when I use only a Python script without referencing a separate .xaml file. I do not encounter these problems using Revit 2025.

There is definitely not a Problem with this one script.

Yes, I know that PyRevit offers many forms, but I want to use my own custom forms in Dynamo as well, so I can maintain a consistent UI throughout.

I didn’t tested with pyrevit 4.8

In the output window, running the command (CTRL+Click on the button) doesn’t show anything special.

I have been experiencing frequent crashes with Dynamo and occasionally with Revit lately. I suspect the issue might be caused by having both IronPython 2 and 3 installed with Dynamo.
But this I also had with Revit 2025.

script.py

# -*- coding: utf-8 -*-
__title__   = "03.02 - Reuse Forms"
__doc__     = """Version = 1.0
Date    = 24.11.2024
________________________________________________________________
Description:
Learn how to reuse your custom forms in all your pyRevit tools
________________________________________________________________
Author: Damjan Podgorelec"""

from Autodesk.Revit.DB import *
from dp_forms import dp_alert

doc = __revit__.ActiveUIDocument.Document  # type: Document

dp_alert('dp Error Message', sub_msg='Sub Message', title='Reusable Form Works!', exitscript=True)
print('Hello WPF World')

Alert.xaml

<Window Title="EF-First WPF Form"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="Auto" Width="300" MinHeight="100"
        WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
        SizeToContent="Height">

    <StackPanel Margin="10">
        <TextBlock x:Name="UI_msg" Text="Error Message" Margin="0,0,0,10" 
                   TextWrapping="Wrap" FontWeight="Bold" FontSize="16" />
        <TextBlock x:Name="UI_submsg" TextWrapping="Wrap" Margin="0,0,0,10" />
        <Image x:Name="UI_img" Margin="0,0,0,10" Height="Auto" Visibility="Collapsed" />
        <Separator Margin="0,0,0,10" />
        <Button Content="Close" Width="100" Margin="0,0,0,10" Click="UIe_btn_run" />
    </StackPanel>
</Window>

Supporting Library Code

# -*- coding: utf-8 -*-
__title__   = "03.01 - Alert"
__doc__     = """Version = 1.0
Date    = 24.10.2024
________________________________________________________________
Description:
Learn how to create Alerts form that includes 
- Error Heading and SubMessage
- Image (optional)
- Button
- ExitScript Functionality
________________________________________________________________
Author: Damjan Podgorelec"""

from Autodesk.Revit.DB import *
from pyrevit import forms
import wpf, os, sys
from System.Windows import Window, Visibility
from System.Windows.Media.Imaging import BitmapImage
from System import Uri

PATH_SCRIPT = os.path.dirname(__file__)

class dp_alert(Window):
    def __init__(self, msg, sub_msg="", image_path="", title='EF Alert Form', exitscript=False):
        path_xaml_file = os.path.join(PATH_SCRIPT, 'Alert.xaml')
        wpf.LoadComponent(self, path_xaml_file)
        self.Title = title
        self.UI_msg.Text = msg
        self.UI_submsg.Text = sub_msg or ""
        if image_path:
            self.UI_img.Source = BitmapImage(Uri(image_path))
            self.UI_img.Visibility = Visibility.Visible
        self.exitscript = exitscript
        self.ShowDialog()

    def UIe_btn_run(self, sender, e):
        self.Close()
        if self.exitscript:
            sys.exit()

Then you have to remove the line (you’re not using the module anyway):

And you should also use clr to add the references to the various .NET assemblies if you want to make this thing portable.

But what do you need WPF windows in Dynamo for?
I used to use Dynamo to automate things and reduce user input as much as possible; Dynamo player could handle the ui for the necessary input…

Anyway, I don’t see anything wrong with the code, I’ll try to see if I can reproduce your issue if I have some spare time.

@ErikFrits do you see anything strange? Also, can I ask you why you use code behind instead of bindings to populate the controls texts and image? Accessing the controls directly ruins one of the few good things WPF has to offer, the ability to separate the presentation from the business logic… or is it just because it is one of the first examples and you’ll get there eventually?