Skip to content

Commit ff63a0b

Browse files
greuelpiratKeboo
andauthored
Set Dialog-Task-Result after IsOpen to prevent "DialogHost is already open." (#1750)
* set _dialogTaskCompletionSource after IsOpen with parameter via DialogSession * Cleaning up DialogClosingEventArgs ctor Added additional unit test for opening and closing the dialog host Co-authored-by: Kevin Bost <[email protected]>
1 parent a434693 commit ff63a0b

File tree

4 files changed

+65
-18
lines changed

4 files changed

+65
-18
lines changed

MaterialDesignThemes.Wpf.Tests/DialogHostTests.cs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,22 @@ public async Task CanOpenDialogWithShowMethodAndCloseWithIsOpen()
6363
Assert.False(_dialogHost.IsOpen);
6464
}
6565

66+
[StaFact]
67+
public async Task CanCloseDialogWithRoutedEvent()
68+
{
69+
Guid closeParameter = Guid.NewGuid();
70+
Task<object> showTask = _dialogHost.ShowDialog("Content");
71+
DialogSession session = _dialogHost.CurrentSession;
72+
Assert.False(session.IsEnded);
73+
74+
DialogHost.CloseDialogCommand.Execute(closeParameter, _dialogHost);
75+
76+
Assert.False(_dialogHost.IsOpen);
77+
Assert.Null(_dialogHost.CurrentSession);
78+
Assert.True(session.IsEnded);
79+
Assert.Equal(closeParameter, await showTask);
80+
}
81+
6682
[StaFact]
6783
public async Task DialogHostExposesSessionAsProperty()
6884
{
@@ -210,9 +226,34 @@ public void WhenDialogHostIsUnloadedIsOpenRemainsTrue()
210226
Assert.True(_dialogHost.IsOpen);
211227
}
212228

213-
private class TestDialog : Control
229+
[StaFact]
230+
[Description("Issue 1750")]
231+
public async Task WhenSettingIsOpenToFalseItReturnsClosingParameterToShow()
232+
{
233+
Guid closeParameter = Guid.NewGuid();
234+
235+
Task<object> showTask = _dialogHost.ShowDialog("Content");
236+
_dialogHost.CurrentSession.CloseParameter = closeParameter;
237+
238+
_dialogHost.IsOpen = false;
239+
240+
Assert.Equal(closeParameter, await showTask);
241+
}
242+
243+
[StaFact]
244+
[Description("Issue 1750")]
245+
public async Task WhenClosingDialogReturnValueCanBeSpecifiedInClosingEventHandler()
214246
{
215-
public void CloseDialog() => DialogHost.CloseDialogCommand.Execute(null, this);
247+
Guid closeParameter = Guid.NewGuid();
248+
249+
Task<object> showTask = _dialogHost.ShowDialog("Content", (object sender, DialogClosingEventArgs args) =>
250+
{
251+
args.Session.CloseParameter = closeParameter;
252+
});
253+
254+
DialogHost.CloseDialogCommand.Execute(null, _dialogHost);
255+
256+
Assert.Equal(closeParameter, await showTask);
216257
}
217258
}
218259
}

MaterialDesignThemes.Wpf/DialogClosingEventArgs.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ namespace MaterialDesignThemes.Wpf
55
{
66
public class DialogClosingEventArgs : RoutedEventArgs
77
{
8-
public DialogClosingEventArgs(DialogSession session, object parameter, RoutedEvent routedEvent) : base(routedEvent)
8+
[Obsolete("Use DialogClosingEventArgs(DialogSession, RoutedEvent), the parameter should be set on the DialogSession.CloseParameter")]
9+
public DialogClosingEventArgs(DialogSession session, object parameter, RoutedEvent routedEvent)
10+
: this(session, routedEvent)
11+
{ }
12+
13+
public DialogClosingEventArgs(DialogSession session, RoutedEvent routedEvent) : base(routedEvent)
914
{
1015
Session = session ?? throw new ArgumentNullException(nameof(session));
11-
12-
Parameter = parameter;
1316
}
1417

1518
/// <summary>
@@ -28,7 +31,7 @@ public void Cancel()
2831
/// <summary>
2932
/// Gets the parameter originally provided to <see cref="DialogHost.CloseDialogCommand"/>/
3033
/// </summary>
31-
public object Parameter { get; }
34+
public object Parameter => Session.CloseParameter;
3235

3336
/// <summary>
3437
/// Allows interaction with the current dialog session.

MaterialDesignThemes.Wpf/DialogHost.cs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ static DialogHost()
7575
DefaultStyleKeyProperty.OverrideMetadata(typeof(DialogHost), new FrameworkPropertyMetadata(typeof(DialogHost)));
7676
}
7777

78-
#region .Show overloads
78+
#region Show overloads
7979

8080
/// <summary>
8181
/// Shows a modal dialog. To use, a <see cref="DialogHost"/> instance must be in a visual tree (typically this may be specified towards the root of a Window's XAML).
@@ -249,12 +249,12 @@ private static void IsOpenPropertyChangedCallback(DependencyObject dependencyObj
249249
dialogHost._currentSnackbarMessageQueueUnPauseAction();
250250
dialogHost._currentSnackbarMessageQueueUnPauseAction = null;
251251
}
252+
253+
var closeParameter = dialogHost.CurrentSession.CloseParameter;
252254
dialogHost.CurrentSession.IsEnded = true;
253255
dialogHost.CurrentSession = null;
254256
//NB: _dialogTaskCompletionSource is only set in the case where the dialog is shown with Show
255-
//To get into this case you need to display the dialog with Show and then hide it by setting IsOpen to false
256-
//Setting this here ensures the other
257-
dialogHost._dialogTaskCompletionSource?.TrySetResult(null);
257+
dialogHost._dialogTaskCompletionSource?.TrySetResult(closeParameter);
258258

259259
// Don't attempt to Invoke if _restoreFocusDialogClose hasn't been assigned yet. Can occur
260260
// if the MainWindow has started up minimized. Even when Show() has been called, this doesn't
@@ -578,8 +578,9 @@ internal void AssertTargetableContent()
578578

579579
internal void Close(object parameter)
580580
{
581-
var dialogClosingEventArgs = new DialogClosingEventArgs(CurrentSession, parameter, DialogClosingEvent);
581+
var dialogClosingEventArgs = new DialogClosingEventArgs(CurrentSession, DialogClosingEvent);
582582

583+
CurrentSession.CloseParameter = parameter;
583584
CurrentSession.IsEnded = true;
584585

585586
//multiple ways of calling back that the dialog is closing:
@@ -592,16 +593,13 @@ internal void Close(object parameter)
592593
DialogClosingCallback?.Invoke(this, dialogClosingEventArgs);
593594
_asyncShowClosingEventHandler?.Invoke(this, dialogClosingEventArgs);
594595

595-
596-
if (!dialogClosingEventArgs.IsCancelled)
597-
{
598-
_dialogTaskCompletionSource?.TrySetResult(parameter);
599-
SetCurrentValue(IsOpenProperty, false);
600-
}
601-
else
596+
if (dialogClosingEventArgs.IsCancelled)
602597
{
603598
CurrentSession.IsEnded = false;
599+
return;
604600
}
601+
602+
SetCurrentValue(IsOpenProperty, false);
605603
}
606604

607605
/// <summary>

MaterialDesignThemes.Wpf/DialogSession.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ internal DialogSession(DialogHost owner)
2222
/// Client code cannot set this directly, this is internally managed. To end the dialog session use <see cref="Close()"/>.
2323
/// </remarks>
2424
public bool IsEnded { get; internal set; }
25+
26+
/// <summary>
27+
/// The parameter passed to the <see cref="DialogHost.CloseDialogCommand" /> and return by <see cref="DialogHost.Show(object)"/>
28+
/// </summary>
29+
internal object CloseParameter { get; set; }
2530

2631
/// <summary>
2732
/// Gets the <see cref="DialogHost.DialogContent"/> which is currently displayed, so this could be a view model or a UI element.

0 commit comments

Comments
 (0)