-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
244 additions
and
187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,209 +1,26 @@ | ||
using Prism.Commands; | ||
using Prism.Common; | ||
using Prism.Dialogs.Xaml; | ||
using Prism.Mvvm; | ||
using Prism.Navigation; | ||
|
||
#nullable enable | ||
namespace Prism.Dialogs; | ||
|
||
/// <summary> | ||
/// Provides the ability to display dialogs from ViewModels. | ||
/// Provides a default scoped implementation of the <see cref="IDialogService"/>. | ||
/// </summary> | ||
public sealed class DialogService : IDialogService | ||
public sealed class DialogService : DialogServiceBase | ||
{ | ||
private readonly IContainerProvider _container; | ||
private readonly IPageAccessor _pageAccessor; | ||
|
||
/// <summary> | ||
/// Creates a new instance of the <see cref="DialogService"/> for Maui Applications | ||
/// </summary> | ||
/// <param name="container">The <see cref="IContainerProvider"/> that will be used to help resolve the Dialog Views.</param> | ||
/// <param name="pageAccessor">The <see cref="IPageAccessor"/> used to determine where in the Navigation Stack we need to process the Dialog.</param> | ||
/// <exception cref="ArgumentNullException">Throws when any constructor arguments are null.</exception> | ||
public DialogService(IContainerProvider container, IPageAccessor pageAccessor) | ||
public DialogService(IPageAccessor pageAccessor) | ||
{ | ||
ArgumentNullException.ThrowIfNull(container); | ||
ArgumentNullException.ThrowIfNull(pageAccessor); | ||
_container = container; | ||
_pageAccessor = pageAccessor; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public void ShowDialog(string name, IDialogParameters parameters, DialogCallback callback) | ||
{ | ||
IDialogContainer? dialogModal = null; | ||
try | ||
{ | ||
parameters = UriParsingHelper.GetSegmentParameters(name, parameters ?? new DialogParameters()); | ||
|
||
// This needs to be resolved when called as a Module could load any time | ||
// and register new dialogs | ||
var registry = _container.Resolve<IDialogViewRegistry>(); | ||
var view = registry.CreateView(_container, UriParsingHelper.GetSegmentName(name)) as View | ||
?? throw new ViewCreationException(name, ViewType.Dialog); | ||
|
||
var currentPage = _pageAccessor.Page; | ||
dialogModal = _container.Resolve<IDialogContainer>(); | ||
IDialogContainer.DialogStack.Add(dialogModal); | ||
var dialogAware = GetDialogController(view); | ||
|
||
async Task DialogAware_RequestClose(IDialogResult outResult) | ||
{ | ||
bool didCloseDialog = true; | ||
try | ||
{ | ||
var result = await CloseDialogAsync(outResult ?? new DialogResult(), currentPage, dialogModal); | ||
if (result.Exception is DialogException de && de.Message == DialogException.CanCloseIsFalse) | ||
{ | ||
didCloseDialog = false; | ||
return; | ||
} | ||
|
||
await callback.Invoke(result); | ||
GC.Collect(); | ||
} | ||
catch (DialogException dex) | ||
{ | ||
if (dex.Message == DialogException.CanCloseIsFalse) | ||
{ | ||
didCloseDialog = false; | ||
return; | ||
} | ||
|
||
var result = new DialogResult | ||
{ | ||
Exception = dex, | ||
Parameters = parameters, | ||
Result = ButtonResult.None | ||
}; | ||
|
||
if (dex.Message != DialogException.CanCloseIsFalse) | ||
{ | ||
await DialogService.InvokeError(callback, dex, parameters); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
await DialogService.InvokeError(callback, ex, parameters); | ||
} | ||
finally | ||
{ | ||
if (didCloseDialog && dialogModal is not null) | ||
{ | ||
IDialogContainer.DialogStack.Remove(dialogModal); | ||
} | ||
} | ||
} | ||
|
||
DialogUtilities.InitializeListener(dialogAware, DialogAware_RequestClose); | ||
|
||
dialogAware.OnDialogOpened(parameters); | ||
|
||
if (!parameters.TryGetValue<bool>(KnownDialogParameters.CloseOnBackgroundTapped, out var closeOnBackgroundTapped)) | ||
{ | ||
var dialogLayoutCloseOnBackgroundTapped = DialogLayout.GetCloseOnBackgroundTapped(view); | ||
if (dialogLayoutCloseOnBackgroundTapped.HasValue) | ||
{ | ||
closeOnBackgroundTapped = dialogLayoutCloseOnBackgroundTapped.Value; | ||
} | ||
} | ||
|
||
var dismissCommand = new DelegateCommand(() => dialogAware.RequestClose.Invoke(), dialogAware.CanCloseDialog); | ||
|
||
PageNavigationService.NavigationSource = PageNavigationSource.DialogService; | ||
dialogModal.ConfigureLayout(_pageAccessor.Page, view, closeOnBackgroundTapped, dismissCommand, parameters); | ||
PageNavigationService.NavigationSource = PageNavigationSource.Device; | ||
|
||
MvvmHelpers.InvokeViewAndViewModelAction<IActiveAware>(currentPage, aa => aa.IsActive = false); | ||
MvvmHelpers.InvokeViewAndViewModelAction<IActiveAware>(view, aa => aa.IsActive = true); | ||
} | ||
catch (Exception ex) | ||
{ | ||
callback.Invoke(ex); | ||
} | ||
} | ||
|
||
private static async Task InvokeError(DialogCallback callback, Exception exception, IDialogParameters parameters) | ||
{ | ||
var result = new DialogResult | ||
{ | ||
Parameters = parameters, | ||
Exception = exception, | ||
Result = ButtonResult.None | ||
}; | ||
await callback.Invoke(result); | ||
} | ||
|
||
private static async Task<IDialogResult> CloseDialogAsync(IDialogResult result, Page currentPage, IDialogContainer dialogModal) | ||
{ | ||
try | ||
{ | ||
PageNavigationService.NavigationSource = PageNavigationSource.DialogService; | ||
|
||
result ??= new DialogResult(); | ||
if (result.Parameters is null) | ||
{ | ||
result = new DialogResult | ||
{ | ||
Exception = result.Exception, | ||
Parameters = new DialogParameters(), | ||
Result = result.Result | ||
}; | ||
} | ||
|
||
var view = dialogModal.DialogView; | ||
var dialogAware = GetDialogController(view); | ||
|
||
if (!dialogAware.CanCloseDialog()) | ||
{ | ||
throw new DialogException(DialogException.CanCloseIsFalse); | ||
} | ||
|
||
PageNavigationService.NavigationSource = PageNavigationSource.DialogService; | ||
await dialogModal.DoPop(currentPage); | ||
PageNavigationService.NavigationSource = PageNavigationSource.Device; | ||
|
||
MvvmHelpers.InvokeViewAndViewModelAction<IActiveAware>(view, aa => aa.IsActive = false); | ||
MvvmHelpers.InvokeViewAndViewModelAction<IActiveAware>(currentPage, aa => aa.IsActive = true); | ||
dialogAware.OnDialogClosed(); | ||
|
||
return result; | ||
} | ||
catch (DialogException) | ||
{ | ||
throw; | ||
} | ||
catch (Exception ex) | ||
{ | ||
return new DialogResult | ||
{ | ||
Exception = ex, | ||
Parameters = result.Parameters, | ||
Result = result.Result | ||
}; | ||
} | ||
finally | ||
{ | ||
PageNavigationService.NavigationSource = PageNavigationSource.Device; | ||
} | ||
} | ||
|
||
private static IDialogAware GetDialogController(View view) | ||
{ | ||
if (view is IDialogAware viewAsDialogAware) | ||
{ | ||
return viewAsDialogAware; | ||
} | ||
else if (view.BindingContext is null) | ||
{ | ||
throw new DialogException(DialogException.NoViewModel); | ||
} | ||
else if (view.BindingContext is IDialogAware dialogAware) | ||
{ | ||
return dialogAware; | ||
} | ||
|
||
throw new DialogException(DialogException.ImplementIDialogAware); | ||
} | ||
protected override Page? GetCurrentPage() => _pageAccessor.Page; | ||
} |
Oops, something went wrong.