Das Problem:
Beim Öffnen eines modalen WPF-Fensters (Window.ShowDialog()) aus dem WinForms-Hauptthread wird das Fenster gelegentlich vollständig weiß/leer geöffnet.
- Der Fensterrand und die Titelleiste sind sichtbar.
- Der Inhaltsbereich ist weiß.
- Entscheidende Beobachtung: Der logische Baum scheint zu existieren (Cursor wechselt zu I-Beam über Textfeldern, Pfeil über Schaltflächen), aber es wird nichts gerendert.
- Problemumgehung: Wenn ich die Größe des Fensters manuell durch Ziehen des Rahmens ändere, wird der Inhalt sofort angezeigt.
Das Problem tritt nur nach einem bestimmten komplexen Szenario auf, das das Öffnen/Schließen mehrerer Hybridfenster und aktiver Hintergrundthreads (Datenagent, Messenger) umfasst. Es sieht aus wie ein Message Pump Starv> oder ein Layout-Deadlock zwischen WinForms und WPF-Dispatchern.
Was ich bisher festgestellt habe:
- Keine Ausnahmen: Es gibt keine unbehandelten Ausnahmen im Ausgabefenster. Ich hatte zuvor InvalidOperationException-Spam (Cross-Thread-Zugriff), aber ich habe es behoben, indem ich die Heartbeat-/Hintergrundaktualisierungen der Benutzeroberfläche geschützt habe. Das Protokoll ist sauber.
- Kein GDI-Leck: Die Anzahl der GDI-Objekte ist niedrig (~200).
- Kein Treiberproblem: Ich habe System.Windows.Interop.RenderMode.SoftwareOnly erzwungen, aber das weiße Fenster bleibt bestehen.
- Das Fenster „treten“: Code im Loaded-Ereignis zu InvalidateVisual(), UpdateLayout() hinzugefügt und die Breite programmgesteuert um 0,1 Pixel über Dispatcher.BeginInvoke geändert (bei verschiedenen Prioritäten: Loaded, Render, ContextIdle).
- Ergebnis: Die programmgesteuerte Größenänderung führt zu nichts. Nur die Größenänderung per physischer Maus funktioniert.
- Z-Order/Topmost: Setze Topmost explizit auf false, um Luftraumprobleme zu vermeiden.
- Warteschlangen leeren: Vor dem Aufruf von .ShowDialog() habe ich versucht, System.Windows.Forms.Application.DoEvents() und aufzurufen WpfApplication.Current.Dispatcher.Invoke(...) zum Löschen ausstehender Nachrichten.
- Vorinitialisierung: Die Sequenz „SecurityHandle()“, „Show()“, „Hide()“ wurde vor ShowDialog() ausprobiert, um die Erstellung der zugrunde liegenden HWND- und DirectX-Oberfläche zu erzwingen.
- Entfernen von SizeToContent: Es wurde ein Konflikt zwischen SizeToContent und der manuellen Größeneinstellung in Loaded vermutet, aber das Entfernen löste den Hunger nicht.
und andere Unendlichkeitsversuche.
Die zum Öffnen des WPF-Fensters aus WinForms verwendete Methode:
Code C#
Code: Select all
public static bool ShowContextedWindow(object viewModel)
{
var win = new DialogWindow()
{
Content = viewModel,
DataContext = viewModel,
WindowStartupLocation = WindowStartupLocation.CenterScreen,
Topmost = false
};
var helper = new WindowInteropHelper(win);
helper.Owner = System.Windows.Forms.Form.ActiveForm.Handle;
ElementHost.EnableModelessKeyboardInterop(win);
System.Windows.Forms.Application.DoEvents();
return win.ShowDialog() == true;
}
Warum friert die WPF-Rendering-Pipeline ein (verarbeitet WM_PAINT nicht?), wenn sie modal aus WinForms unter Last geöffnet wird, und warum wird sie durch die programmgesteuerte Größenänderung nicht aktiviert, während die manuelle Größenänderung funktioniert? Gibt es spezielle „Nuklearoptionen“, um den WPF-Dispatcher zu zwingen, die Renderwarteschlange in diesem speziellen Hybrid-Deadlock-Szenario zu verarbeiten?
Mobile version