feat: clean up code, allow empty host, simplify z index calculation.
This commit is contained in:
@@ -40,6 +40,6 @@ public partial class DialogWithActionViewModel: ObservableObject, IDialogContext
|
||||
|
||||
private async Task ShowDialog()
|
||||
{
|
||||
await DialogBox.ShowOverlayModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(new DialogWithActionViewModel(), "GlobalHost");
|
||||
await OverlayDialog.ShowModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(new DialogWithActionViewModel());
|
||||
}
|
||||
}
|
||||
@@ -45,25 +45,25 @@ public class DialogDemoViewModel: ObservableObject
|
||||
|
||||
private void ShowGlobalOverlayDialog()
|
||||
{
|
||||
DialogBox.ShowOverlay<DialogWithAction, DialogWithActionViewModel>(new DialogWithActionViewModel(), "GlobalHost");
|
||||
OverlayDialog.Show<DialogWithAction, DialogWithActionViewModel>(new DialogWithActionViewModel());
|
||||
}
|
||||
|
||||
private async Task ShowGlobalModalDialog()
|
||||
{
|
||||
var result = await DialogBox.ShowModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(DialogViewModel);
|
||||
var result = await Dialog.ShowModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(DialogViewModel);
|
||||
Result = result;
|
||||
}
|
||||
|
||||
private async Task ShowGlobalOverlayModalDialog()
|
||||
{
|
||||
Result = await DialogBox.ShowOverlayModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(DialogViewModel, "GlobalHost");
|
||||
Result = await OverlayDialog.ShowModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(DialogViewModel);
|
||||
}
|
||||
|
||||
private async Task ShowLocalOverlayModalDialog()
|
||||
{
|
||||
var vm = new DialogWithActionViewModel();
|
||||
var result = await DialogBox.ShowOverlayModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(
|
||||
DialogViewModel, "LocalHost", new DialogOptions(){ ExtendToClientArea = true });
|
||||
var result = await OverlayDialog.ShowModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(
|
||||
DialogViewModel, new DialogOptions() { ExtendToClientArea = true }, "LocalHost");
|
||||
Result = result;
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@
|
||||
<converters:ViewLocator />
|
||||
</ContentControl.ContentTemplate>
|
||||
</ContentControl>
|
||||
<u:OverlayDialogHost Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" HostId="GlobalHost" />
|
||||
<u:OverlayDialogHost Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2"/>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
|
||||
@@ -6,39 +6,34 @@ using Avalonia.Media;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
public static class DialogBox
|
||||
public static class Dialog
|
||||
{
|
||||
public static async Task<TResult?> ShowModalAsync<TView, TViewModel, TResult>(TViewModel vm)
|
||||
where TView : Control, new()
|
||||
{
|
||||
var window = new DialogWindow()
|
||||
{
|
||||
Content = new TView(),
|
||||
DataContext = vm,
|
||||
};
|
||||
|
||||
var lifetime = Application.Current?.ApplicationLifetime;
|
||||
if (lifetime is IClassicDesktopStyleApplicationLifetime classLifetime)
|
||||
{
|
||||
var main = classLifetime.MainWindow;
|
||||
if (main is null)
|
||||
var window = new DialogWindow
|
||||
{
|
||||
Content = new TView { DataContext = vm },
|
||||
DataContext = vm,
|
||||
};
|
||||
if (classLifetime.MainWindow is not { } main)
|
||||
{
|
||||
window.Show();
|
||||
return default(TResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = await window.ShowDialog<TResult>(main);
|
||||
return result;
|
||||
return default;
|
||||
}
|
||||
var result = await window.ShowDialog<TResult>(main);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return default(TResult);
|
||||
}
|
||||
|
||||
return default(TResult);
|
||||
}
|
||||
|
||||
public static async Task<TResult> ShowModalAsync<TView, TViewModel, TResult>(Window owner, TViewModel vm) where
|
||||
TView: Control, new()
|
||||
public static async Task<TResult> ShowModalAsync<TView, TViewModel, TResult>(Window owner, TViewModel? vm)
|
||||
where TView: Control, new()
|
||||
{
|
||||
var window = new DialogWindow
|
||||
{
|
||||
@@ -47,9 +42,11 @@ public static class DialogBox
|
||||
};
|
||||
return await window.ShowDialog<TResult>(owner);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Task<TResult> ShowOverlayModalAsync<TView, TViewModel, TResult>(TViewModel vm, string hostId)
|
||||
public static class OverlayDialog
|
||||
{
|
||||
public static Task<TResult> ShowModalAsync<TView, TViewModel, TResult>(TViewModel vm, string? hostId = null)
|
||||
where TView : Control, new()
|
||||
{
|
||||
var t = new DialogControl()
|
||||
@@ -62,8 +59,7 @@ public static class DialogBox
|
||||
return t.ShowAsync<TResult>();
|
||||
}
|
||||
|
||||
public static Task<TResult> ShowOverlayModalAsync<TView, TViewModel, TResult>(TViewModel vm, string hostId,
|
||||
DialogOptions options)
|
||||
public static Task<TResult> ShowModalAsync<TView, TViewModel, TResult>(TViewModel vm, DialogOptions options, string? hostId = null)
|
||||
where TView : Control, new()
|
||||
{
|
||||
var t = new DialogControl()
|
||||
@@ -78,7 +74,7 @@ public static class DialogBox
|
||||
return t.ShowAsync<TResult>();
|
||||
}
|
||||
|
||||
public static void ShowOverlay<TView, TViewModel>(TViewModel vm, string hostId)
|
||||
public static void Show<TView, TViewModel>(TViewModel vm, string? hostId = null)
|
||||
where TView: Control, new()
|
||||
{
|
||||
var t = new DialogControl()
|
||||
@@ -90,7 +86,7 @@ public static class DialogBox
|
||||
host?.AddDialog(t);
|
||||
}
|
||||
|
||||
public static void ShowOverlay<TView, TViewModel>(TViewModel vm, string hostId, DialogOptions options)
|
||||
public static void Show<TView, TViewModel>(TViewModel vm, DialogOptions options, string? hostId)
|
||||
where TView: Control, new()
|
||||
{
|
||||
var t = new DialogControl()
|
||||
@@ -1,13 +1,9 @@
|
||||
using System.Collections.Specialized;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Shapes;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Utilities;
|
||||
using Avalonia.VisualTree;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
@@ -53,7 +49,7 @@ public class OverlayDialogHost : Canvas
|
||||
for (int i = 0; i < _masks.Count; i++)
|
||||
{
|
||||
_masks[i].Width = this.Bounds.Width;
|
||||
_masks[i].Width = this.Bounds.Height;
|
||||
_masks[i].Height = this.Bounds.Height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,9 +90,9 @@ public class OverlayDialogHost : Canvas
|
||||
{
|
||||
this.Children.Add(control);
|
||||
_dialogs.Add(control);
|
||||
control.ZIndex = Children.Last().ZIndex + 1;
|
||||
control.OnClose += OnDialogClose;
|
||||
control.OnLayerChange += OnDialogLayerChange;
|
||||
ResetZIndices();
|
||||
}
|
||||
|
||||
private void OnDialogClose(object sender, object? e)
|
||||
@@ -124,32 +120,31 @@ public class OverlayDialogHost : Canvas
|
||||
}
|
||||
}
|
||||
}
|
||||
ResetZIndices();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a dialog as a modal dialog to the host
|
||||
/// </summary>
|
||||
/// <param name="control"></param>
|
||||
internal void AddModalDialog(DialogControl control)
|
||||
{
|
||||
var mask = CreateOverlayMask();
|
||||
_masks.Add(mask);
|
||||
_modalDialogs.Add(control);
|
||||
int start = _dialogs.LastOrDefault()?.ZIndex ?? 1;
|
||||
for (int i = 0; i < _masks.Count; i += 1)
|
||||
{
|
||||
_masks[i].ZIndex = start + 2 * i;
|
||||
_modalDialogs[i].ZIndex = start + 2 * i + 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _masks.Count-1; i++)
|
||||
{
|
||||
_masks[i].Opacity = 0.5;
|
||||
}
|
||||
|
||||
ResetZIndices();
|
||||
this.Children.Add(mask);
|
||||
this.Children.Add(control);
|
||||
control.OnClose += OnDialogClose;
|
||||
control.OnLayerChange += OnDialogLayerChange;
|
||||
}
|
||||
|
||||
// Handle dialog layer change event
|
||||
private void OnDialogLayerChange(object sender, DialogLayerChangeEventArgs e)
|
||||
{
|
||||
if (sender is not DialogControl control)
|
||||
@@ -188,4 +183,21 @@ public class OverlayDialogHost : Canvas
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void ResetZIndices()
|
||||
{
|
||||
int index = 0;
|
||||
for ( int i = 0; i< _dialogs.Count; i++)
|
||||
{
|
||||
_dialogs[i].ZIndex = index;
|
||||
index++;
|
||||
}
|
||||
for(int i = 0; i< _masks.Count; i++)
|
||||
{
|
||||
_masks[i].ZIndex = index;
|
||||
index++;
|
||||
_modalDialogs[i].ZIndex = index;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,20 +4,39 @@ namespace Ursa.Controls;
|
||||
|
||||
internal static class OverlayDialogManager
|
||||
{
|
||||
private static ConcurrentDictionary<string, OverlayDialogHost> _hosts = new();
|
||||
private static OverlayDialogHost? _defaultHost;
|
||||
private static readonly ConcurrentDictionary<string, OverlayDialogHost> Hosts = new();
|
||||
|
||||
public static void RegisterOverlayDialogHost(OverlayDialogHost host, string id)
|
||||
public static void RegisterOverlayDialogHost(OverlayDialogHost host, string? id)
|
||||
{
|
||||
_hosts.TryAdd(id, host);
|
||||
if (id == null)
|
||||
{
|
||||
if (_defaultHost != null)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot register multiple OverlayDialogHost with empty HostId");
|
||||
}
|
||||
_defaultHost = host;
|
||||
return;
|
||||
}
|
||||
Hosts.TryAdd(id, host);
|
||||
}
|
||||
|
||||
public static void UnregisterOverlayDialogHost(string id)
|
||||
public static void UnregisterOverlayDialogHost(string? id)
|
||||
{
|
||||
_hosts.TryRemove(id, out _);
|
||||
if (id is null)
|
||||
{
|
||||
_defaultHost = null;
|
||||
return;
|
||||
}
|
||||
Hosts.TryRemove(id, out _);
|
||||
}
|
||||
|
||||
public static OverlayDialogHost? GetOverlayDialogHost(string id)
|
||||
public static OverlayDialogHost? GetOverlayDialogHost(string? id)
|
||||
{
|
||||
return _hosts.TryGetValue(id, out var host) ? host : null;
|
||||
if (id is null)
|
||||
{
|
||||
return _defaultHost;
|
||||
}
|
||||
return Hosts.TryGetValue(id, out var host) ? host : null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user