feat: clean up code, allow empty host, simplify z index calculation.

This commit is contained in:
rabbitism
2024-01-24 01:27:47 +08:00
parent e06d6ffb25
commit 9441d7577e
6 changed files with 81 additions and 54 deletions

View File

@@ -40,6 +40,6 @@ public partial class DialogWithActionViewModel: ObservableObject, IDialogContext
private async Task ShowDialog() private async Task ShowDialog()
{ {
await DialogBox.ShowOverlayModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(new DialogWithActionViewModel(), "GlobalHost"); await OverlayDialog.ShowModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(new DialogWithActionViewModel());
} }
} }

View File

@@ -45,25 +45,25 @@ public class DialogDemoViewModel: ObservableObject
private void ShowGlobalOverlayDialog() private void ShowGlobalOverlayDialog()
{ {
DialogBox.ShowOverlay<DialogWithAction, DialogWithActionViewModel>(new DialogWithActionViewModel(), "GlobalHost"); OverlayDialog.Show<DialogWithAction, DialogWithActionViewModel>(new DialogWithActionViewModel());
} }
private async Task ShowGlobalModalDialog() private async Task ShowGlobalModalDialog()
{ {
var result = await DialogBox.ShowModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(DialogViewModel); var result = await Dialog.ShowModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(DialogViewModel);
Result = result; Result = result;
} }
private async Task ShowGlobalOverlayModalDialog() 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() private async Task ShowLocalOverlayModalDialog()
{ {
var vm = new DialogWithActionViewModel(); var vm = new DialogWithActionViewModel();
var result = await DialogBox.ShowOverlayModalAsync<DialogWithAction, DialogWithActionViewModel, bool>( var result = await OverlayDialog.ShowModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(
DialogViewModel, "LocalHost", new DialogOptions(){ ExtendToClientArea = true }); DialogViewModel, new DialogOptions() { ExtendToClientArea = true }, "LocalHost");
Result = result; Result = result;
} }
} }

View File

@@ -80,7 +80,7 @@
<converters:ViewLocator /> <converters:ViewLocator />
</ContentControl.ContentTemplate> </ContentControl.ContentTemplate>
</ContentControl> </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> </Grid>
</UserControl> </UserControl>

View File

@@ -6,39 +6,34 @@ using Avalonia.Media;
namespace Ursa.Controls; namespace Ursa.Controls;
public static class DialogBox public static class Dialog
{ {
public static async Task<TResult?> ShowModalAsync<TView, TViewModel, TResult>(TViewModel vm) public static async Task<TResult?> ShowModalAsync<TView, TViewModel, TResult>(TViewModel vm)
where TView : Control, new() where TView : Control, new()
{ {
var window = new DialogWindow()
{
Content = new TView(),
DataContext = vm,
};
var lifetime = Application.Current?.ApplicationLifetime; var lifetime = Application.Current?.ApplicationLifetime;
if (lifetime is IClassicDesktopStyleApplicationLifetime classLifetime) if (lifetime is IClassicDesktopStyleApplicationLifetime classLifetime)
{ {
var main = classLifetime.MainWindow; var window = new DialogWindow
if (main is null) {
Content = new TView { DataContext = vm },
DataContext = vm,
};
if (classLifetime.MainWindow is not { } main)
{ {
window.Show(); window.Show();
return default(TResult); return default;
}
else
{
var result = await window.ShowDialog<TResult>(main);
return result;
} }
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 public static async Task<TResult> ShowModalAsync<TView, TViewModel, TResult>(Window owner, TViewModel? vm)
TView: Control, new() where TView: Control, new()
{ {
var window = new DialogWindow var window = new DialogWindow
{ {
@@ -47,9 +42,11 @@ public static class DialogBox
}; };
return await window.ShowDialog<TResult>(owner); 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() where TView : Control, new()
{ {
var t = new DialogControl() var t = new DialogControl()
@@ -62,8 +59,7 @@ public static class DialogBox
return t.ShowAsync<TResult>(); return t.ShowAsync<TResult>();
} }
public static Task<TResult> ShowOverlayModalAsync<TView, TViewModel, TResult>(TViewModel vm, string hostId, public static Task<TResult> ShowModalAsync<TView, TViewModel, TResult>(TViewModel vm, DialogOptions options, string? hostId = null)
DialogOptions options)
where TView : Control, new() where TView : Control, new()
{ {
var t = new DialogControl() var t = new DialogControl()
@@ -78,7 +74,7 @@ public static class DialogBox
return t.ShowAsync<TResult>(); 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() where TView: Control, new()
{ {
var t = new DialogControl() var t = new DialogControl()
@@ -90,7 +86,7 @@ public static class DialogBox
host?.AddDialog(t); 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() where TView: Control, new()
{ {
var t = new DialogControl() var t = new DialogControl()

View File

@@ -1,13 +1,9 @@
using System.Collections.Specialized;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Utilities; using Avalonia.Utilities;
using Avalonia.VisualTree;
namespace Ursa.Controls; namespace Ursa.Controls;
@@ -53,7 +49,7 @@ public class OverlayDialogHost : Canvas
for (int i = 0; i < _masks.Count; i++) for (int i = 0; i < _masks.Count; i++)
{ {
_masks[i].Width = this.Bounds.Width; _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); this.Children.Add(control);
_dialogs.Add(control); _dialogs.Add(control);
control.ZIndex = Children.Last().ZIndex + 1;
control.OnClose += OnDialogClose; control.OnClose += OnDialogClose;
control.OnLayerChange += OnDialogLayerChange; control.OnLayerChange += OnDialogLayerChange;
ResetZIndices();
} }
private void OnDialogClose(object sender, object? e) 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) internal void AddModalDialog(DialogControl control)
{ {
var mask = CreateOverlayMask(); var mask = CreateOverlayMask();
_masks.Add(mask); _masks.Add(mask);
_modalDialogs.Add(control); _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++) for (int i = 0; i < _masks.Count-1; i++)
{ {
_masks[i].Opacity = 0.5; _masks[i].Opacity = 0.5;
} }
ResetZIndices();
this.Children.Add(mask); this.Children.Add(mask);
this.Children.Add(control); this.Children.Add(control);
control.OnClose += OnDialogClose; control.OnClose += OnDialogClose;
control.OnLayerChange += OnDialogLayerChange; control.OnLayerChange += OnDialogLayerChange;
} }
// Handle dialog layer change event
private void OnDialogLayerChange(object sender, DialogLayerChangeEventArgs e) private void OnDialogLayerChange(object sender, DialogLayerChangeEventArgs e)
{ {
if (sender is not DialogControl control) 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++;
}
}
} }

View File

@@ -4,20 +4,39 @@ namespace Ursa.Controls;
internal static class OverlayDialogManager 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;
} }
} }