lepoco/wpfui · error · InvalidOperationException
Cannot change DialogHostEx while the dialog is being shown.
Error message
Cannot change DialogHostEx while the dialog is being shown.
What it means
Thrown by the ContentDialog.DialogHostEx setter when you attempt to reassign the host while a previous ShowAsync call is still in flight. The dialog tracks an IsShowing flag (Tcs != null and not completed) and refuses host mutations mid-display to avoid tearing down the visual tree under a live await. It is a state-machine guard, not a data error.
Source
Thrown at src/Wpf.Ui/Controls/ContentDialog/ContentDialog.cs:679
/// </summary>
/// <exception cref="InvalidOperationException">
/// Thrown if trying to set DialogHostEx when DialogHost is already set, or if trying to change DialogHostEx while the dialog is being shown.
/// </exception>
public ContentDialogHost? DialogHostEx
{
get => _dialogHostEx;
set
{
if (_dialogHost is not null)
{
throw new InvalidOperationException(
"Cannot set DialogHostEx when DialogHost is already set."
);
}
if (IsShowing)
{
throw new InvalidOperationException(
"Cannot change DialogHostEx while the dialog is being shown."
);
}
if (!ReferenceEquals(_dialogHostEx, value))
{
_dialogHostEx = value;
}
UpdateIsLegacyHost();
}
}
[Obsolete("ContentPresenter is deprecated. Please use DialogHost instead.")]
public ContentPresenter? ContentPresenter { get; set; } = default;
protected TaskCompletionSource<ContentDialogResult>? Tcs { get; set; }
View on GitHub (pinned to ffebacd610)
Solutions
- Await the previous ShowAsync() call to completion before assigning DialogHostEx.
- Set DialogHostEx once at construction / XAML time and do not rebind it.
- If you must swap hosts, create a new ContentDialog instance per host rather than mutating the existing one.
- Guard the assignment yourself: if (!dialog.IsShowing) dialog.DialogHostEx = host; — note IsShowing is private, so track the ShowAsync task yourself.
Example fix
// before _ = dialog.ShowAsync(); dialog.DialogHostEx = otherHost; // throws // after await dialog.ShowAsync(); dialog.DialogHostEx = otherHost;
Defensive patterns
Strategy: validation
Validate before calling
// Track the in-flight task yourself (IsShowing is private)
private Task<ContentDialogResult>? _showTask;
if (_showTask is null || _showTask.IsCompleted)
dialog.DialogHostEx = newHost;
else
Debug.WriteLine("Cannot change DialogHostEx: dialog is showing."); Prevention
- Always await ShowAsync before mutating DialogHost/DialogHostEx.
- Do not data-bind DialogHostEx to a frequently-changing view-model property.
- Prefer one host per ContentDialog for the dialog's lifetime.
When it happens
Trigger: Assigning dialog.DialogHostEx = newHost while the Task returned by a prior dialog.ShowAsync() has not yet completed (i.e. the dialog is still on screen or the TCS is pending). Also fires if a binding pushes a new value to DialogHostEx during display.
Common situations: Reusing a single ContentDialog instance across windows and swapping the host in a view-model; data-binding DialogHostEx to a property that changes on navigation; calling ShowAsync without await and immediately reassigning the host.
Related errors
- DialogHost was not set
- Only one ContentDialogHost instance is allowed per Window.
- Unable to find the base directory of the application.
- Unable to determine the window source.
- Cannot apply backdrop effect if ExtendsContentIntoTitleBar i
AI-assisted analysis of lepoco/wpfui@ffebacd610 (2026-08-13).
Data as JSON: /api/errors/4b300e22c30bbfd6.
Report an issue: GitHub.