Skip to content

Commit 0160aea

Browse files
HenJiggbombipappooKeboo
authored
Add the DialogHost close method. (#2029)
* Add the DialogHost close method. * Resolve naming conflicts. * Update MaterialDesignThemes.Wpf/DialogHost.cs Co-authored-by: bombipappoo <[email protected]> * Update MaterialDesignThemes.Wpf/DialogHost.cs Co-authored-by: bombipappoo <[email protected]> * Updating Close methods * Renamed method to simply be Close Added unit tests. * Fixing broken unit tests Co-authored-by: bombipappoo <[email protected]> Co-authored-by: Kevin Bost <[email protected]>
1 parent 1f0929b commit 0160aea

File tree

3 files changed

+103
-12
lines changed

3 files changed

+103
-12
lines changed

MaterialDesignThemes.Wpf.Tests/DialogHostTests.cs

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public async Task CanCloseDialogWithRoutedEvent()
7070
Task<object> showTask = _dialogHost.ShowDialog("Content");
7171
DialogSession session = _dialogHost.CurrentSession;
7272
Assert.False(session.IsEnded);
73-
73+
7474
DialogHost.CloseDialogCommand.Execute(closeParameter, _dialogHost);
7575

7676
Assert.False(_dialogHost.IsOpen);
@@ -126,7 +126,7 @@ public async Task WhenNoDialogsMatchIdentifierItThrows()
126126

127127
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => DialogHost.Show("Content", id));
128128

129-
Assert.Equal($"No loaded DialogHost have an {nameof(DialogHost.Identifier)} property matching dialogIdentifier argument.", ex.Message);
129+
Assert.Equal($"No loaded DialogHost have an {nameof(DialogHost.Identifier)} property matching dialogIdentifier ('{id}') argument.", ex.Message);
130130
}
131131

132132
[StaFact]
@@ -142,7 +142,7 @@ public async Task WhenMultipleDialogHostsHaveTheSameIdentifierItThrows()
142142
otherDialogHost.RaiseEvent(new RoutedEventArgs(FrameworkElement.UnloadedEvent));
143143

144144

145-
Assert.Equal("Multiple viable DialogHosts. Specify a unique Identifier on each DialogHost, especially where multiple Windows are a concern.", ex.Message);
145+
Assert.Equal("Multiple viable DialogHosts. Specify a unique Identifier on each DialogHost, especially where multiple Windows are a concern.", ex.Message);
146146
}
147147

148148
[StaFact]
@@ -255,5 +255,69 @@ public async Task WhenClosingDialogReturnValueCanBeSpecifiedInClosingEventHandle
255255

256256
Assert.Equal(closeParameter, await showTask);
257257
}
258+
259+
[StaFact]
260+
[Description("Pull Request 2029")]
261+
public void WhenClosingDialogItThrowsWhenNoInstancesLoaded()
262+
{
263+
_dialogHost.RaiseEvent(new RoutedEventArgs(FrameworkElement.UnloadedEvent));
264+
265+
var ex = Assert.Throws<InvalidOperationException>(() => DialogHost.Close(null));
266+
Assert.Equal("No loaded DialogHost instances.", ex.Message);
267+
}
268+
269+
[StaFact]
270+
[Description("Pull Request 2029")]
271+
public void WhenClosingDialogWithInvalidIdentifierItThrowsWhenNoMatchingInstances()
272+
{
273+
object id = Guid.NewGuid();
274+
var ex = Assert.Throws<InvalidOperationException>(() => DialogHost.Close(id));
275+
Assert.Equal($"No loaded DialogHost have an Identifier property matching dialogIdentifier ('{id}') argument.", ex.Message);
276+
}
277+
278+
[StaFact]
279+
[Description("Pull Request 2029")]
280+
public void WhenClosingDialogWithMultipleDialogHostsItThrowsTooManyMatchingInstances()
281+
{
282+
var secondInstance = new DialogHost();
283+
try
284+
{
285+
secondInstance.RaiseEvent(new RoutedEventArgs(FrameworkElement.LoadedEvent));
286+
var ex = Assert.Throws<InvalidOperationException>(() => DialogHost.Close(null));
287+
Assert.Equal("Multiple viable DialogHosts. Specify a unique Identifier on each DialogHost, especially where multiple Windows are a concern.", ex.Message);
288+
}
289+
finally
290+
{
291+
secondInstance.RaiseEvent(new RoutedEventArgs(FrameworkElement.UnloadedEvent));
292+
}
293+
}
294+
295+
[StaFact]
296+
[Description("Pull Request 2029")]
297+
public void WhenClosingDialogThatIsNotOpenItThrowsDialogNotOpen()
298+
{
299+
var ex = Assert.Throws<InvalidOperationException>(() => DialogHost.Close(null));
300+
Assert.Equal("DialogHost is not open.", ex.Message);
301+
}
302+
303+
[StaFact]
304+
[Description("Pull Request 2029")]
305+
public void WhenClosingDialogWithParameterItPassesParameterToHandlers()
306+
{
307+
object parameter = Guid.NewGuid();
308+
object closingParameter = null;
309+
_dialogHost.DialogClosing += DialogClosing;
310+
_dialogHost.IsOpen = true;
311+
312+
DialogHost.Close(null, parameter);
313+
314+
Assert.Equal(parameter, closingParameter);
315+
316+
void DialogClosing(object sender, DialogClosingEventArgs eventArgs)
317+
{
318+
closingParameter = eventArgs.Parameter;
319+
}
320+
}
321+
258322
}
259323
}

MaterialDesignThemes.Wpf/DialogHost.cs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,19 +166,46 @@ public static Task<object> Show(object content, object dialogIdentifier, DialogC
166166
/// <returns>Task result is the parameter used to close the dialog, typically what is passed to the <see cref="CloseDialogCommand"/> command.</returns>
167167
public static async Task<object> Show(object content, object dialogIdentifier, DialogOpenedEventHandler openedEventHandler, DialogClosingEventHandler closingEventHandler)
168168
{
169-
if (content == null) throw new ArgumentNullException(nameof(content));
169+
if (content is null) throw new ArgumentNullException(nameof(content));
170+
return await GetInstance(dialogIdentifier).ShowInternal(content, openedEventHandler, closingEventHandler);
171+
}
172+
173+
/// <summary>
174+
/// Close a modal dialog.
175+
/// </summary>
176+
/// <param name="dialogIdentifier"> of the instance where the dialog should be closed. Typically this will match an identifer set in XAML. </param>
177+
public static void Close(object dialogIdentifier)
178+
=> Close(dialogIdentifier, null);
170179

180+
/// <summary>
181+
/// Close a modal dialog.
182+
/// </summary>
183+
/// <param name="dialogIdentifier"> of the instance where the dialog should be closed. Typically this will match an identifer set in XAML. </param>
184+
/// <param name="parameter"> to provide to close handler</param>
185+
public static void Close(object dialogIdentifier, object parameter)
186+
{
187+
DialogHost dialogHost = GetInstance(dialogIdentifier);
188+
if (dialogHost.CurrentSession is { } currentSession)
189+
{
190+
currentSession.Close(parameter);
191+
return;
192+
}
193+
throw new InvalidOperationException("DialogHost is not open.");
194+
}
195+
196+
private static DialogHost GetInstance(object dialogIdentifier)
197+
{
171198
if (LoadedInstances.Count == 0)
172199
throw new InvalidOperationException("No loaded DialogHost instances.");
173200
LoadedInstances.First().Dispatcher.VerifyAccess();
174201

175202
var targets = LoadedInstances.Where(dh => dialogIdentifier == null || Equals(dh.Identifier, dialogIdentifier)).ToList();
176203
if (targets.Count == 0)
177-
throw new InvalidOperationException($"No loaded DialogHost have an {nameof(Identifier)} property matching {nameof(dialogIdentifier)} argument.");
204+
throw new InvalidOperationException($"No loaded DialogHost have an {nameof(Identifier)} property matching {nameof(dialogIdentifier)} ('{dialogIdentifier}') argument.");
178205
if (targets.Count > 1)
179-
throw new InvalidOperationException("Multiple viable DialogHosts. Specify a unique Identifier on each DialogHost, especially where multiple Windows are a concern.");
206+
throw new InvalidOperationException("Multiple viable DialogHosts. Specify a unique Identifier on each DialogHost, especially where multiple Windows are a concern.");
180207

181-
return await targets[0].ShowInternal(content, openedEventHandler, closingEventHandler);
208+
return targets[0];
182209
}
183210

184211
internal async Task<object> ShowInternal(object content, DialogOpenedEventHandler openedEventHandler, DialogClosingEventHandler closingEventHandler)
@@ -579,7 +606,7 @@ internal void AssertTargetableContent()
579606
"Content cannot be passed to a dialog via the OpenDialog if DialogContent already has a binding.");
580607
}
581608

582-
internal void Close(object parameter)
609+
internal void InternalClose(object parameter)
583610
{
584611
var dialogClosingEventArgs = new DialogClosingEventArgs(CurrentSession, DialogClosingEvent);
585612

@@ -636,7 +663,7 @@ protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
636663
private void ContentCoverGridOnMouseLeftButtonUp(object sender, MouseButtonEventArgs mouseButtonEventArgs)
637664
{
638665
if (CloseOnClickAway && CurrentSession != null)
639-
Close(CloseOnClickAwayParameter);
666+
InternalClose(CloseOnClickAwayParameter);
640667
}
641668

642669
private void OpenDialogHandler(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
@@ -689,7 +716,7 @@ private void CloseDialogHandler(object sender, ExecutedRoutedEventArgs executedR
689716
{
690717
if (executedRoutedEventArgs.Handled) return;
691718

692-
Close(executedRoutedEventArgs.Parameter);
719+
InternalClose(executedRoutedEventArgs.Parameter);
693720

694721
executedRoutedEventArgs.Handled = true;
695722
}

MaterialDesignThemes.Wpf/DialogSession.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public void Close()
5555
{
5656
if (IsEnded) throw new InvalidOperationException("Dialog session has ended.");
5757

58-
_owner.Close(null);
58+
_owner.InternalClose(null);
5959
}
6060

6161
/// <summary>
@@ -67,7 +67,7 @@ public void Close(object parameter)
6767
{
6868
if (IsEnded) throw new InvalidOperationException("Dialog session has ended.");
6969

70-
_owner.Close(parameter);
70+
_owner.InternalClose(parameter);
7171
}
7272
}
7373
}

0 commit comments

Comments
 (0)