|
|
|
|
// Copyright (c) 2019 Blazored (https://github.com/Blazored)
|
|
|
|
|
// Copyright (c) 2020 Jonny Larsson (https://github.com/MudBlazor/MudBlazor)
|
|
|
|
|
// Copyright (c) 2021 improvements by Meinrad Recheis
|
|
|
|
|
// See https://github.com/Blazored
|
|
|
|
|
// License: MIT
|
|
|
|
|
|
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
|
using Connected.Components;
|
|
|
|
|
using Microsoft.AspNetCore.Components;
|
|
|
|
|
|
|
|
|
|
namespace Connected
|
|
|
|
|
{
|
|
|
|
|
public class DialogService : IDialogService
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// This internal wrapper components prevents overwriting parameters of once
|
|
|
|
|
/// instanciated dialog instances
|
|
|
|
|
/// </summary>
|
|
|
|
|
private class DialogHelperComponent : IComponent
|
|
|
|
|
{
|
|
|
|
|
const string ChildContent = nameof(ChildContent);
|
|
|
|
|
RenderFragment _renderFragment;
|
|
|
|
|
RenderHandle _renderHandle;
|
|
|
|
|
void IComponent.Attach(RenderHandle renderHandle) => _renderHandle = renderHandle;
|
|
|
|
|
Task IComponent.SetParametersAsync(ParameterView parameters)
|
|
|
|
|
{
|
|
|
|
|
if (_renderFragment == null)
|
|
|
|
|
{
|
|
|
|
|
if (parameters.TryGetValue(ChildContent, out _renderFragment))
|
|
|
|
|
{
|
|
|
|
|
_renderHandle.Render(_renderFragment);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
public static RenderFragment Wrap(RenderFragment renderFragment)
|
|
|
|
|
=> new RenderFragment(builder =>
|
|
|
|
|
{
|
|
|
|
|
builder.OpenComponent<DialogHelperComponent>(1);
|
|
|
|
|
builder.AddAttribute(2, ChildContent, renderFragment);
|
|
|
|
|
builder.CloseComponent();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public event Action<IDialogReference> OnDialogInstanceAdded;
|
|
|
|
|
public event Action<IDialogReference, DialogResult> OnDialogCloseRequested;
|
|
|
|
|
|
|
|
|
|
public IDialogReference Show<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() where T : ComponentBase
|
|
|
|
|
{
|
|
|
|
|
return Show<T>(string.Empty, new DialogParameters(), new DialogOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IDialogReference Show<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(string title) where T : ComponentBase
|
|
|
|
|
{
|
|
|
|
|
return Show<T>(title, new DialogParameters(), new DialogOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IDialogReference Show<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(string title, DialogOptions options) where T : ComponentBase
|
|
|
|
|
{
|
|
|
|
|
return Show<T>(title, new DialogParameters(), options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IDialogReference Show<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(string title, DialogParameters parameters) where T : ComponentBase
|
|
|
|
|
{
|
|
|
|
|
return Show<T>(title, parameters, new DialogOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IDialogReference Show<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(string title, DialogParameters parameters, DialogOptions options) where T : ComponentBase
|
|
|
|
|
{
|
|
|
|
|
return Show(typeof(T), title, parameters, options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IDialogReference Show([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type contentComponent)
|
|
|
|
|
{
|
|
|
|
|
return Show(contentComponent, string.Empty, new DialogParameters(), new DialogOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IDialogReference Show([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type contentComponent, string title)
|
|
|
|
|
{
|
|
|
|
|
return Show(contentComponent, title, new DialogParameters(), new DialogOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IDialogReference Show([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type contentComponent, string title, DialogOptions options)
|
|
|
|
|
{
|
|
|
|
|
return Show(contentComponent, title, new DialogParameters(), options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IDialogReference Show([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type contentComponent, string title, DialogParameters parameters)
|
|
|
|
|
{
|
|
|
|
|
return Show(contentComponent, title, parameters, new DialogOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IDialogReference Show([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type contentComponent, string title, DialogParameters parameters, DialogOptions options)
|
|
|
|
|
{
|
|
|
|
|
if (!typeof(ComponentBase).IsAssignableFrom(contentComponent))
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException($"{contentComponent?.FullName} must be a Blazor Component");
|
|
|
|
|
}
|
|
|
|
|
var dialogReference = CreateReference();
|
|
|
|
|
|
|
|
|
|
var dialogContent = DialogHelperComponent.Wrap(new RenderFragment(builder =>
|
|
|
|
|
{
|
|
|
|
|
var i = 0;
|
|
|
|
|
builder.OpenComponent(i++, contentComponent);
|
|
|
|
|
foreach (var parameter in parameters)
|
|
|
|
|
{
|
|
|
|
|
builder.AddAttribute(i++, parameter.Key, parameter.Value);
|
|
|
|
|
}
|
|
|
|
|
builder.AddComponentReferenceCapture(i++, inst => { dialogReference.InjectDialog(inst); });
|
|
|
|
|
builder.CloseComponent();
|
|
|
|
|
}));
|
|
|
|
|
var dialogInstance = new RenderFragment(builder =>
|
|
|
|
|
{
|
|
|
|
|
builder.OpenComponent<DialogInstance>(0);
|
|
|
|
|
builder.SetKey(dialogReference.Id);
|
|
|
|
|
builder.AddAttribute(1, "Options", options);
|
|
|
|
|
builder.AddAttribute(2, "Title", title);
|
|
|
|
|
builder.AddAttribute(3, "Content", dialogContent);
|
|
|
|
|
builder.AddAttribute(4, "Id", dialogReference.Id);
|
|
|
|
|
builder.CloseComponent();
|
|
|
|
|
});
|
|
|
|
|
dialogReference.InjectRenderFragment(dialogInstance);
|
|
|
|
|
OnDialogInstanceAdded?.Invoke(dialogReference);
|
|
|
|
|
|
|
|
|
|
return dialogReference;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<IDialogReference> ShowAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() where T : ComponentBase
|
|
|
|
|
{
|
|
|
|
|
return ShowAsync<T>(string.Empty, new DialogParameters(), new DialogOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<IDialogReference> ShowAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(string title) where T : ComponentBase
|
|
|
|
|
{
|
|
|
|
|
return ShowAsync<T>(title, new DialogParameters(), new DialogOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<IDialogReference> ShowAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(string title, DialogOptions options) where T : ComponentBase
|
|
|
|
|
{
|
|
|
|
|
return ShowAsync<T>(title, new DialogParameters(), options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<IDialogReference> ShowAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(string title, DialogParameters parameters) where T : ComponentBase
|
|
|
|
|
{
|
|
|
|
|
return ShowAsync<T>(title, parameters, new DialogOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<IDialogReference> ShowAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(string title, DialogParameters parameters, DialogOptions options) where T : ComponentBase
|
|
|
|
|
{
|
|
|
|
|
return ShowAsync(typeof(T), title, parameters, options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<IDialogReference> ShowAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type contentComponent)
|
|
|
|
|
{
|
|
|
|
|
return ShowAsync(contentComponent, string.Empty, new DialogParameters(), new DialogOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<IDialogReference> ShowAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type contentComponent, string title)
|
|
|
|
|
{
|
|
|
|
|
return ShowAsync(contentComponent, title, new DialogParameters(), new DialogOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<IDialogReference> ShowAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type contentComponent, string title, DialogOptions options)
|
|
|
|
|
{
|
|
|
|
|
return ShowAsync(contentComponent, title, new DialogParameters(), options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<IDialogReference> ShowAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type contentComponent, string title, DialogParameters parameters)
|
|
|
|
|
{
|
|
|
|
|
return ShowAsync(contentComponent, title, parameters, new DialogOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<IDialogReference> ShowAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type contentComponent, string title, DialogParameters parameters, DialogOptions options)
|
|
|
|
|
{
|
|
|
|
|
var dialogReference = Show(contentComponent, title, parameters, options);
|
|
|
|
|
|
|
|
|
|
//Do not wait forever, what if render fails because of some internal exception and we will never release the method.
|
|
|
|
|
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5));
|
|
|
|
|
var token = cancellationTokenSource.Token;
|
|
|
|
|
await using (token.Register(() => dialogReference.RenderCompleteTaskCompletionSource.TrySetResult(false)))
|
|
|
|
|
{
|
|
|
|
|
await dialogReference.RenderCompleteTaskCompletionSource.Task;
|
|
|
|
|
|
|
|
|
|
return dialogReference;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<bool?> ShowMessageBox(string title, string message, string yesText = "OK",
|
|
|
|
|
string noText = null, string cancelText = null, DialogOptions options = null)
|
|
|
|
|
{
|
|
|
|
|
return this.ShowMessageBox(new MessageBoxOptions
|
|
|
|
|
{
|
|
|
|
|
Title = title,
|
|
|
|
|
Message = message,
|
|
|
|
|
YesText = yesText,
|
|
|
|
|
NoText = noText,
|
|
|
|
|
CancelText = cancelText,
|
|
|
|
|
}, options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<bool?> ShowMessageBox(string title, MarkupString markupMessage, string yesText = "OK",
|
|
|
|
|
string noText = null, string cancelText = null, DialogOptions options = null)
|
|
|
|
|
{
|
|
|
|
|
return this.ShowMessageBox(new MessageBoxOptions
|
|
|
|
|
{
|
|
|
|
|
Title = title,
|
|
|
|
|
MarkupMessage = markupMessage,
|
|
|
|
|
YesText = yesText,
|
|
|
|
|
NoText = noText,
|
|
|
|
|
CancelText = cancelText,
|
|
|
|
|
}, options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<bool?> ShowMessageBox(MessageBoxOptions messageBoxOptions, DialogOptions options = null)
|
|
|
|
|
{
|
|
|
|
|
var parameters = new DialogParameters()
|
|
|
|
|
{
|
|
|
|
|
[nameof(MessageBoxOptions.Title)] = messageBoxOptions.Title,
|
|
|
|
|
[nameof(MessageBoxOptions.Message)] = messageBoxOptions.Message,
|
|
|
|
|
[nameof(MessageBoxOptions.MarkupMessage)] = messageBoxOptions.MarkupMessage,
|
|
|
|
|
[nameof(MessageBoxOptions.CancelText)] = messageBoxOptions.CancelText,
|
|
|
|
|
[nameof(MessageBoxOptions.NoText)] = messageBoxOptions.NoText,
|
|
|
|
|
[nameof(MessageBoxOptions.YesText)] = messageBoxOptions.YesText,
|
|
|
|
|
};
|
|
|
|
|
var reference = await ShowAsync<MessageBox>(parameters: parameters, options: options, title: messageBoxOptions.Title);
|
|
|
|
|
var result = await reference.Result;
|
|
|
|
|
if (result.Cancelled || result.Data is not bool data)
|
|
|
|
|
return null;
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Close(DialogReference dialog)
|
|
|
|
|
{
|
|
|
|
|
Close(dialog, DialogResult.Ok<object>(null));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void Close(DialogReference dialog, DialogResult result)
|
|
|
|
|
{
|
|
|
|
|
OnDialogCloseRequested?.Invoke(dialog, result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual IDialogReference CreateReference()
|
|
|
|
|
{
|
|
|
|
|
return new DialogReference(Guid.NewGuid(), this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[ExcludeFromCodeCoverage]
|
|
|
|
|
public class MessageBoxOptions
|
|
|
|
|
{
|
|
|
|
|
public string Title { get; set; }
|
|
|
|
|
public string Message { get; set; }
|
|
|
|
|
public MarkupString MarkupMessage { get; set; }
|
|
|
|
|
public string YesText { get; set; } = "OK";
|
|
|
|
|
public string NoText { get; set; }
|
|
|
|
|
public string CancelText { get; set; }
|
|
|
|
|
}
|
|
|
|
|
}
|