Repository navigation
Description
The WPF windows of the Revit thread draw again after the API upgrades a family or a template of an earlier Revit version.
Document.LoadFamily, Application.NewFamilyDocument, and Application.OpenDocumentFile upgrade a file of an earlier version, and Revit shows the "Model Upgrade" progress dialog while it does.
The dialog runs a message loop of its own: PeekMessage(PM_NOREMOVE), then GetMessageW, and it dispatches only a list of messages it knows.
The list includes WM_PAINT, WM_TIMER, and the registered DispatcherProcessQueue of the WPF dispatcher, and drops every other message.
It drops MilChannelNotify, the message the WPF render thread posts to MediaContextNotificationWindow after a frame.
WPF presents the next frame of the thread only after it reads that notification, and waits for it with no timeout.
A toolkit scope around the upgrading calls can post the message again once the calls end.
Steps to reproduce
- In Revit 2026, show a WPF window on the Revit thread that draws continuously, such as an element with a
DoubleAnimationofOpacitythat repeats forever. - In an external event or a
RevitApiUiTest, callApplication.NewFamilyDocumentwithC:\ProgramData\Autodesk\RVT 2025\Family Templates\English\Metric Detail Item.rft, or load a family saved in Revit 2025. - Change the background of the window after the call returns.
✔️ Expected Behavior
The window draws the new background, and the ribbon and every WPF pane of Revit draw their changes.
❌ Actual Behavior
- The window, the ribbon, and the main window of Revit 2026 and 2027 show the frame of the moment the upgrade ran.
- Input, the dispatcher, and its timers run, and the model views draw as usual.
- The windows draw again only when a WPF window of the thread changes its size, because
HwndTarget.OnResizeof a layered or a resized window callsMediaContext.CompleteRender, which reads the notification from the render channel directly.
A balloon ofComponentManager.InfoCenterPaletteManager.ShowBalloonis such a window, which is why showing a balloon afterLoadFamilyis a known way around it.
| Revit | Upgrading call | Upgrades that lost the notification |
|---|---|---|
| 2026.5 | LoadFamily of a 2025 family: from an external event, from an external command, with and without IFamilyLoadOptions |
9 of 9 |
| 2026.5 | OpenDocumentFile of a 2025 family |
1 of 1 |
| 2026.5 | NewFamilyDocument from a 2025 template |
2 of 2 |
| 2027.2 | LoadFamily of a 2025 family |
3 of 3 |
| 2025.4 | NewFamilyDocument from a 2024 template, in a RevitApiUiTest |
1 of 1 |
| 2026.5 | LoadFamily of a family saved in 2026 |
0 of 2: Revit retrieves no message |
After the loss, MediaContext of the thread stays in InterlockState.WaitingForResponse for as long as the measurement watched, over 30 s.
Posting MilChannelNotify to the MediaContextNotificationWindow of the Revit thread after the upgrade restored the drawing in every run.
The message loop of the upgrade
- The loop is the routine at
RevitMFC.dll+0x959F0in 2026.5, called from the progress callbacks ofPersistenceDB.dllthroughRevitDB.dll. - It dispatches
WM_PAINT,WM_ACTIVATE,WM_TIMER,WM_SYSTIMER,WM_NCMOUSEHOVERtoWM_MOUSELEAVE,0x360to0x37F, someWM_SYSCOMMANDvalues,0x31F,0x400and0x401withwParam0xBABE,0x8002,0x8003, and the registeredCRSM_QueuedFunction,DispatcherProcessQueue, andTaskBarButtonCreated. RevitMFC.dllregistersMilChannelNotifybeside these three in Revit 2025, 2026, and 2027, and no code of the module reads the registered value.
Environment
Revit 2025.4, 2026.5, and 2027.2 with their user interface, Nice3point.Revit.Toolkit 2025.2.3, 2026.1.3, and 2027.0.3, Nice3point.TUnit.Revit x.1.8.
Activity