feat: OverlayDialogHost remake: support host with same id in different toplevel. support modal status propagation.
This commit is contained in:
@@ -20,7 +20,13 @@
|
|||||||
<converters:IconNameToPathConverter x:Key="IconConverter" />
|
<converters:IconNameToPathConverter x:Key="IconConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Panel>
|
<Panel>
|
||||||
|
<Panel.Styles>
|
||||||
|
<Style Selector="Grid.Blur">
|
||||||
|
<Setter Property="Effect" Value="blur(10)"></Setter>
|
||||||
|
</Style>
|
||||||
|
</Panel.Styles>
|
||||||
<Grid
|
<Grid
|
||||||
|
Classes.Blur="{Binding $parent[u:UrsaWindow].(u:OverlayDialogHost.IsInModalStatus)}"
|
||||||
ColumnDefinitions="Auto, *" >
|
ColumnDefinitions="Auto, *" >
|
||||||
<Border
|
<Border
|
||||||
Padding="8 4"
|
Padding="8 4"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<Setter Property="FontFamily" Value="{DynamicResource DefaultFontFamily}" />
|
<Setter Property="FontFamily" Value="{DynamicResource DefaultFontFamily}" />
|
||||||
<Setter Property="ExtendClientAreaTitleBarHeightHint" Value="-1" />
|
<Setter Property="ExtendClientAreaTitleBarHeightHint" Value="-1" />
|
||||||
<Setter Property="ExtendClientAreaToDecorationsHint" Value="True" />
|
<Setter Property="ExtendClientAreaToDecorationsHint" Value="True" />
|
||||||
|
<Setter Property="u:OverlayDialogHost.IsModalStatusScope" Value="True"/>
|
||||||
<Setter Property="SystemDecorations">
|
<Setter Property="SystemDecorations">
|
||||||
<OnPlatform>
|
<OnPlatform>
|
||||||
<OnPlatform.Default>
|
<OnPlatform.Default>
|
||||||
|
|||||||
@@ -46,4 +46,8 @@ public class OverlayDialogOptions
|
|||||||
public bool ShowCloseButton { get; set; } = true;
|
public bool ShowCloseButton { get; set; } = true;
|
||||||
public bool CanLightDismiss { get; set; }
|
public bool CanLightDismiss { get; set; }
|
||||||
public bool CanDragMove { get; set; } = true;
|
public bool CanDragMove { get; set; } = true;
|
||||||
|
/// <summary>
|
||||||
|
/// The hash code of the top level dialog host. This is used to identify the dialog host if there are multiple dialog hosts with the same id. If this is not provided, the dialog will be added to the first dialog host with the same id.
|
||||||
|
/// </summary>
|
||||||
|
public int? TopLevelHashCode { get; set; }
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@ public static class OverlayDialog
|
|||||||
OverlayDialogOptions? options = null)
|
OverlayDialogOptions? options = null)
|
||||||
where TView : Control, new()
|
where TView : Control, new()
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return;
|
if (host is null) return;
|
||||||
var t = new DefaultDialogControl()
|
var t = new DefaultDialogControl()
|
||||||
{
|
{
|
||||||
@@ -25,7 +25,7 @@ public static class OverlayDialog
|
|||||||
public static void Show(Control control, object? vm, string? hostId = null,
|
public static void Show(Control control, object? vm, string? hostId = null,
|
||||||
OverlayDialogOptions? options = null)
|
OverlayDialogOptions? options = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return;
|
if (host is null) return;
|
||||||
var t = new DefaultDialogControl()
|
var t = new DefaultDialogControl()
|
||||||
{
|
{
|
||||||
@@ -39,7 +39,7 @@ public static class OverlayDialog
|
|||||||
|
|
||||||
public static void Show(object? vm, string? hostId = null, OverlayDialogOptions? options = null)
|
public static void Show(object? vm, string? hostId = null, OverlayDialogOptions? options = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return;
|
if (host is null) return;
|
||||||
var view = host.GetDataTemplate(vm)?.Build(vm);
|
var view = host.GetDataTemplate(vm)?.Build(vm);
|
||||||
if (view is null) view = new ContentControl();
|
if (view is null) view = new ContentControl();
|
||||||
@@ -57,7 +57,7 @@ public static class OverlayDialog
|
|||||||
OverlayDialogOptions? options = null)
|
OverlayDialogOptions? options = null)
|
||||||
where TView: Control, new()
|
where TView: Control, new()
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return;
|
if (host is null) return;
|
||||||
var t = new CustomDialogControl()
|
var t = new CustomDialogControl()
|
||||||
{
|
{
|
||||||
@@ -71,7 +71,7 @@ public static class OverlayDialog
|
|||||||
public static void ShowCustom(Control control, object? vm, string? hostId = null,
|
public static void ShowCustom(Control control, object? vm, string? hostId = null,
|
||||||
OverlayDialogOptions? options = null)
|
OverlayDialogOptions? options = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return;
|
if (host is null) return;
|
||||||
var t = new CustomDialogControl()
|
var t = new CustomDialogControl()
|
||||||
{
|
{
|
||||||
@@ -85,7 +85,7 @@ public static class OverlayDialog
|
|||||||
public static void ShowCustom(object? vm, string? hostId = null,
|
public static void ShowCustom(object? vm, string? hostId = null,
|
||||||
OverlayDialogOptions? options = null)
|
OverlayDialogOptions? options = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return;
|
if (host is null) return;
|
||||||
var view = host.GetDataTemplate(vm)?.Build(vm);
|
var view = host.GetDataTemplate(vm)?.Build(vm);
|
||||||
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
|
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
|
||||||
@@ -103,7 +103,7 @@ public static class OverlayDialog
|
|||||||
OverlayDialogOptions? options = null, CancellationToken? token = default)
|
OverlayDialogOptions? options = null, CancellationToken? token = default)
|
||||||
where TView: Control, new()
|
where TView: Control, new()
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return Task.FromResult(DialogResult.None);
|
if (host is null) return Task.FromResult(DialogResult.None);
|
||||||
var t = new DefaultDialogControl()
|
var t = new DefaultDialogControl()
|
||||||
{
|
{
|
||||||
@@ -118,7 +118,7 @@ public static class OverlayDialog
|
|||||||
public static Task<DialogResult> ShowModal(Control control, object? vm, string? hostId = null,
|
public static Task<DialogResult> ShowModal(Control control, object? vm, string? hostId = null,
|
||||||
OverlayDialogOptions? options = null, CancellationToken? token = default)
|
OverlayDialogOptions? options = null, CancellationToken? token = default)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return Task.FromResult(DialogResult.None);
|
if (host is null) return Task.FromResult(DialogResult.None);
|
||||||
var t = new DefaultDialogControl()
|
var t = new DefaultDialogControl()
|
||||||
{
|
{
|
||||||
@@ -134,7 +134,7 @@ public static class OverlayDialog
|
|||||||
OverlayDialogOptions? options = null, CancellationToken? token = default)
|
OverlayDialogOptions? options = null, CancellationToken? token = default)
|
||||||
where TView: Control, new()
|
where TView: Control, new()
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return Task.FromResult(default(TResult));
|
if (host is null) return Task.FromResult(default(TResult));
|
||||||
var t = new CustomDialogControl()
|
var t = new CustomDialogControl()
|
||||||
{
|
{
|
||||||
@@ -149,7 +149,7 @@ public static class OverlayDialog
|
|||||||
public static Task<TResult?> ShowCustomModal<TResult>(Control control, object? vm, string? hostId = null,
|
public static Task<TResult?> ShowCustomModal<TResult>(Control control, object? vm, string? hostId = null,
|
||||||
OverlayDialogOptions? options = null, CancellationToken? token = default)
|
OverlayDialogOptions? options = null, CancellationToken? token = default)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return Task.FromResult(default(TResult));
|
if (host is null) return Task.FromResult(default(TResult));
|
||||||
var t = new CustomDialogControl()
|
var t = new CustomDialogControl()
|
||||||
{
|
{
|
||||||
@@ -164,7 +164,7 @@ public static class OverlayDialog
|
|||||||
public static Task<TResult?> ShowCustomModal<TResult>(object? vm, string? hostId = null,
|
public static Task<TResult?> ShowCustomModal<TResult>(object? vm, string? hostId = null,
|
||||||
OverlayDialogOptions? options = null, CancellationToken? token = default)
|
OverlayDialogOptions? options = null, CancellationToken? token = default)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return Task.FromResult(default(TResult));
|
if (host is null) return Task.FromResult(default(TResult));
|
||||||
var view = host.GetDataTemplate(vm)?.Build(vm);
|
var view = host.GetDataTemplate(vm)?.Build(vm);
|
||||||
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
|
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
|
||||||
@@ -227,7 +227,7 @@ public static class OverlayDialog
|
|||||||
|
|
||||||
internal static T? Recall<T>(string? hostId) where T: Control
|
internal static T? Recall<T>(string? hostId) where T: Control
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, null);
|
||||||
if (host is null) return null;
|
if (host is null) return null;
|
||||||
var item = host.Recall<T>();
|
var item = host.Recall<T>();
|
||||||
return item;
|
return item;
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ namespace Ursa.Controls;
|
|||||||
public static class Drawer
|
public static class Drawer
|
||||||
{
|
{
|
||||||
public static void Show<TView, TViewModel>(TViewModel vm, string? hostId = null, DrawerOptions? options = null)
|
public static void Show<TView, TViewModel>(TViewModel vm, string? hostId = null, DrawerOptions? options = null)
|
||||||
where TView: Control, new()
|
where TView : Control, new()
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return;
|
if (host is null) return;
|
||||||
var drawer = new DefaultDrawerControl()
|
var drawer = new DefaultDrawerControl
|
||||||
{
|
{
|
||||||
Content = new TView(),
|
Content = new TView(),
|
||||||
DataContext = vm,
|
DataContext = vm
|
||||||
};
|
};
|
||||||
ConfigureDefaultDrawer(drawer, options);
|
ConfigureDefaultDrawer(drawer, options);
|
||||||
host.AddDrawer(drawer);
|
host.AddDrawer(drawer);
|
||||||
@@ -24,12 +24,12 @@ public static class Drawer
|
|||||||
public static void Show(Control control, object? vm, string? hostId = null,
|
public static void Show(Control control, object? vm, string? hostId = null,
|
||||||
DrawerOptions? options = null)
|
DrawerOptions? options = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return;
|
if (host is null) return;
|
||||||
var drawer = new DefaultDrawerControl()
|
var drawer = new DefaultDrawerControl
|
||||||
{
|
{
|
||||||
Content = control,
|
Content = control,
|
||||||
DataContext = vm,
|
DataContext = vm
|
||||||
};
|
};
|
||||||
ConfigureDefaultDrawer(drawer, options);
|
ConfigureDefaultDrawer(drawer, options);
|
||||||
host.AddDrawer(drawer);
|
host.AddDrawer(drawer);
|
||||||
@@ -37,29 +37,30 @@ public static class Drawer
|
|||||||
|
|
||||||
public static void Show(object? vm, string? hostId = null, DrawerOptions? options = null)
|
public static void Show(object? vm, string? hostId = null, DrawerOptions? options = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return;
|
if (host is null) return;
|
||||||
var view = host.GetDataTemplate(vm)?.Build(vm);
|
var view = host.GetDataTemplate(vm)?.Build(vm);
|
||||||
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
|
if (view is null) view = new ContentControl { Padding = new Thickness(24) };
|
||||||
view.DataContext = vm;
|
view.DataContext = vm;
|
||||||
var drawer = new DefaultDrawerControl()
|
var drawer = new DefaultDrawerControl
|
||||||
{
|
{
|
||||||
Content = view,
|
Content = view,
|
||||||
DataContext = vm,
|
DataContext = vm
|
||||||
};
|
};
|
||||||
ConfigureDefaultDrawer(drawer, options);
|
ConfigureDefaultDrawer(drawer, options);
|
||||||
host.AddDrawer(drawer);
|
host.AddDrawer(drawer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<DialogResult> ShowModal<TView, TViewModel>(TViewModel vm, string? hostId = null, DrawerOptions? options = null)
|
public static Task<DialogResult> ShowModal<TView, TViewModel>(TViewModel vm, string? hostId = null,
|
||||||
where TView: Control, new()
|
DrawerOptions? options = null)
|
||||||
|
where TView : Control, new()
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return Task.FromResult(DialogResult.None);
|
if (host is null) return Task.FromResult(DialogResult.None);
|
||||||
var drawer = new DefaultDrawerControl()
|
var drawer = new DefaultDrawerControl
|
||||||
{
|
{
|
||||||
Content = new TView(),
|
Content = new TView(),
|
||||||
DataContext = vm,
|
DataContext = vm
|
||||||
};
|
};
|
||||||
ConfigureDefaultDrawer(drawer, options);
|
ConfigureDefaultDrawer(drawer, options);
|
||||||
host.AddModalDrawer(drawer);
|
host.AddModalDrawer(drawer);
|
||||||
@@ -69,12 +70,12 @@ public static class Drawer
|
|||||||
public static Task<DialogResult> ShowModal(Control control, object? vm, string? hostId = null,
|
public static Task<DialogResult> ShowModal(Control control, object? vm, string? hostId = null,
|
||||||
DrawerOptions? options = null)
|
DrawerOptions? options = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return Task.FromResult(DialogResult.None);
|
if (host is null) return Task.FromResult(DialogResult.None);
|
||||||
var drawer = new DefaultDrawerControl()
|
var drawer = new DefaultDrawerControl
|
||||||
{
|
{
|
||||||
Content = control,
|
Content = control,
|
||||||
DataContext = vm,
|
DataContext = vm
|
||||||
};
|
};
|
||||||
ConfigureDefaultDrawer(drawer, options);
|
ConfigureDefaultDrawer(drawer, options);
|
||||||
host.AddModalDrawer(drawer);
|
host.AddModalDrawer(drawer);
|
||||||
@@ -83,30 +84,31 @@ public static class Drawer
|
|||||||
|
|
||||||
public static Task<DialogResult> ShowModal(object? vm, string? hostId = null, DrawerOptions? options = null)
|
public static Task<DialogResult> ShowModal(object? vm, string? hostId = null, DrawerOptions? options = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return Task.FromResult(DialogResult.None);
|
if (host is null) return Task.FromResult(DialogResult.None);
|
||||||
var view = host.GetDataTemplate(vm)?.Build(vm);
|
var view = host.GetDataTemplate(vm)?.Build(vm);
|
||||||
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
|
if (view is null) view = new ContentControl { Padding = new Thickness(24) };
|
||||||
view.DataContext = vm;
|
view.DataContext = vm;
|
||||||
var drawer = new DefaultDrawerControl()
|
var drawer = new DefaultDrawerControl
|
||||||
{
|
{
|
||||||
Content = view,
|
Content = view,
|
||||||
DataContext = vm,
|
DataContext = vm
|
||||||
};
|
};
|
||||||
ConfigureDefaultDrawer(drawer, options);
|
ConfigureDefaultDrawer(drawer, options);
|
||||||
host.AddModalDrawer(drawer);
|
host.AddModalDrawer(drawer);
|
||||||
return drawer.ShowAsync<DialogResult>();
|
return drawer.ShowAsync<DialogResult>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ShowCustom<TView, TViewModel>(TViewModel vm, string? hostId = null, DrawerOptions? options = null)
|
public static void ShowCustom<TView, TViewModel>(TViewModel vm, string? hostId = null,
|
||||||
where TView: Control, new()
|
DrawerOptions? options = null)
|
||||||
|
where TView : Control, new()
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return;
|
if (host is null) return;
|
||||||
var dialog = new CustomDrawerControl()
|
var dialog = new CustomDrawerControl
|
||||||
{
|
{
|
||||||
Content = new TView(),
|
Content = new TView(),
|
||||||
DataContext = vm,
|
DataContext = vm
|
||||||
};
|
};
|
||||||
ConfigureCustomDrawer(dialog, options);
|
ConfigureCustomDrawer(dialog, options);
|
||||||
host.AddDrawer(dialog);
|
host.AddDrawer(dialog);
|
||||||
@@ -114,12 +116,12 @@ public static class Drawer
|
|||||||
|
|
||||||
public static void ShowCustom(Control control, object? vm, string? hostId = null, DrawerOptions? options = null)
|
public static void ShowCustom(Control control, object? vm, string? hostId = null, DrawerOptions? options = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return;
|
if (host is null) return;
|
||||||
var dialog = new CustomDrawerControl()
|
var dialog = new CustomDrawerControl
|
||||||
{
|
{
|
||||||
Content = control,
|
Content = control,
|
||||||
DataContext = vm,
|
DataContext = vm
|
||||||
};
|
};
|
||||||
ConfigureCustomDrawer(dialog, options);
|
ConfigureCustomDrawer(dialog, options);
|
||||||
host.AddDrawer(dialog);
|
host.AddDrawer(dialog);
|
||||||
@@ -127,60 +129,63 @@ public static class Drawer
|
|||||||
|
|
||||||
public static void ShowCustom(object? vm, string? hostId = null, DrawerOptions? options = null)
|
public static void ShowCustom(object? vm, string? hostId = null, DrawerOptions? options = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return;
|
if (host is null) return;
|
||||||
var view = host.GetDataTemplate(vm)?.Build(vm);
|
var view = host.GetDataTemplate(vm)?.Build(vm);
|
||||||
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
|
if (view is null) view = new ContentControl { Padding = new Thickness(24) };
|
||||||
view.DataContext = vm;
|
view.DataContext = vm;
|
||||||
var dialog = new CustomDrawerControl()
|
var dialog = new CustomDrawerControl
|
||||||
{
|
{
|
||||||
Content = view,
|
Content = view,
|
||||||
DataContext = vm,
|
DataContext = vm
|
||||||
};
|
};
|
||||||
ConfigureCustomDrawer(dialog, options);
|
ConfigureCustomDrawer(dialog, options);
|
||||||
host.AddDrawer(dialog);
|
host.AddDrawer(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<TResult?> ShowCustomModal<TView, TViewModel, TResult>(TViewModel vm, string? hostId = null, DrawerOptions? options = null)
|
public static Task<TResult?> ShowCustomModal<TView, TViewModel, TResult>(TViewModel vm, string? hostId = null,
|
||||||
where TView: Control, new()
|
DrawerOptions? options = null)
|
||||||
|
where TView : Control, new()
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return Task.FromResult<TResult?>(default);
|
if (host is null) return Task.FromResult<TResult?>(default);
|
||||||
var dialog = new CustomDrawerControl()
|
var dialog = new CustomDrawerControl
|
||||||
{
|
{
|
||||||
Content = new TView(),
|
Content = new TView(),
|
||||||
DataContext = vm,
|
DataContext = vm
|
||||||
};
|
};
|
||||||
ConfigureCustomDrawer(dialog, options);
|
ConfigureCustomDrawer(dialog, options);
|
||||||
host.AddModalDrawer(dialog);
|
host.AddModalDrawer(dialog);
|
||||||
return dialog.ShowAsync<TResult?>();
|
return dialog.ShowAsync<TResult?>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<TResult?> ShowCustomModal<TResult>(Control control, object? vm, string? hostId = null, DrawerOptions? options = null)
|
public static Task<TResult?> ShowCustomModal<TResult>(Control control, object? vm, string? hostId = null,
|
||||||
|
DrawerOptions? options = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return Task.FromResult<TResult?>(default);
|
if (host is null) return Task.FromResult<TResult?>(default);
|
||||||
var dialog = new CustomDrawerControl()
|
var dialog = new CustomDrawerControl
|
||||||
{
|
{
|
||||||
Content = control,
|
Content = control,
|
||||||
DataContext = vm,
|
DataContext = vm
|
||||||
};
|
};
|
||||||
ConfigureCustomDrawer(dialog, options);
|
ConfigureCustomDrawer(dialog, options);
|
||||||
host.AddModalDrawer(dialog);
|
host.AddModalDrawer(dialog);
|
||||||
return dialog.ShowAsync<TResult?>();
|
return dialog.ShowAsync<TResult?>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<TResult?> ShowCustomModal<TResult>(object? vm, string? hostId = null, DrawerOptions? options = null)
|
public static Task<TResult?> ShowCustomModal<TResult>(object? vm, string? hostId = null,
|
||||||
|
DrawerOptions? options = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, options?.TopLevelHashCode);
|
||||||
if (host is null) return Task.FromResult<TResult?>(default);
|
if (host is null) return Task.FromResult<TResult?>(default);
|
||||||
var view = host.GetDataTemplate(vm)?.Build(vm);
|
var view = host.GetDataTemplate(vm)?.Build(vm);
|
||||||
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
|
if (view is null) view = new ContentControl { Padding = new Thickness(24) };
|
||||||
view.DataContext = vm;
|
view.DataContext = vm;
|
||||||
var dialog = new CustomDrawerControl()
|
var dialog = new CustomDrawerControl
|
||||||
{
|
{
|
||||||
Content = view,
|
Content = view,
|
||||||
DataContext = vm,
|
DataContext = vm
|
||||||
};
|
};
|
||||||
ConfigureCustomDrawer(dialog, options);
|
ConfigureCustomDrawer(dialog, options);
|
||||||
host.AddModalDrawer(dialog);
|
host.AddModalDrawer(dialog);
|
||||||
@@ -198,6 +203,7 @@ public static class Drawer
|
|||||||
drawer.MinWidth = options.MinWidth ?? 0.0;
|
drawer.MinWidth = options.MinWidth ?? 0.0;
|
||||||
drawer.MaxWidth = options.MaxWidth ?? double.PositiveInfinity;
|
drawer.MaxWidth = options.MaxWidth ?? double.PositiveInfinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.Position is Position.Top or Position.Bottom)
|
if (options.Position is Position.Top or Position.Bottom)
|
||||||
{
|
{
|
||||||
drawer.MinHeight = options.MinHeight ?? 0.0;
|
drawer.MinHeight = options.MinHeight ?? 0.0;
|
||||||
@@ -218,6 +224,7 @@ public static class Drawer
|
|||||||
drawer.MinWidth = options.MinWidth ?? 0.0;
|
drawer.MinWidth = options.MinWidth ?? 0.0;
|
||||||
drawer.MaxWidth = options.MaxWidth ?? double.PositiveInfinity;
|
drawer.MaxWidth = options.MaxWidth ?? double.PositiveInfinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.Position is Position.Top or Position.Bottom)
|
if (options.Position is Position.Top or Position.Bottom)
|
||||||
{
|
{
|
||||||
drawer.MinHeight = options.MinHeight ?? 0.0;
|
drawer.MinHeight = options.MinHeight ?? 0.0;
|
||||||
|
|||||||
@@ -15,4 +15,8 @@ public class DrawerOptions
|
|||||||
public DialogButton Buttons { get; set; } = DialogButton.OKCancel;
|
public DialogButton Buttons { get; set; } = DialogButton.OKCancel;
|
||||||
public string? Title { get; set; }
|
public string? Title { get; set; }
|
||||||
public bool ShowCloseButton { get; set; } = true;
|
public bool ShowCloseButton { get; set; } = true;
|
||||||
|
/// <summary>
|
||||||
|
/// The hash code of the top level dialog host. This is used to identify the dialog host if there are multiple dialog hosts with the same id. If this is not provided, the dialog will be added to the first dialog host with the same id.
|
||||||
|
/// </summary>
|
||||||
|
public int? TopLevelHashCode { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Controls.Notifications;
|
|
||||||
using Avalonia.Styling;
|
|
||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
@@ -18,28 +16,20 @@ public static class MessageBox
|
|||||||
{
|
{
|
||||||
Content = message,
|
Content = message,
|
||||||
Title = title,
|
Title = title,
|
||||||
MessageIcon = icon,
|
MessageIcon = icon
|
||||||
};
|
};
|
||||||
var lifetime = Application.Current?.ApplicationLifetime;
|
var lifetime = Application.Current?.ApplicationLifetime;
|
||||||
if (lifetime is IClassicDesktopStyleApplicationLifetime classLifetime)
|
if (lifetime is not IClassicDesktopStyleApplicationLifetime classLifetime) return MessageBoxResult.None;
|
||||||
{
|
|
||||||
var main = classLifetime.MainWindow;
|
var main = classLifetime.MainWindow;
|
||||||
if (main is null)
|
if (main is null)
|
||||||
{
|
{
|
||||||
messageWindow.Show();
|
messageWindow.Show();
|
||||||
return MessageBoxResult.None;
|
return MessageBoxResult.None;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
var result = await messageWindow.ShowDialog<MessageBoxResult>(main);
|
var result = await messageWindow.ShowDialog<MessageBoxResult>(main);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return MessageBoxResult.None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<MessageBoxResult> ShowAsync(
|
public static async Task<MessageBoxResult> ShowAsync(
|
||||||
Window owner,
|
Window owner,
|
||||||
@@ -52,7 +42,7 @@ public static class MessageBox
|
|||||||
{
|
{
|
||||||
Content = message,
|
Content = message,
|
||||||
Title = title,
|
Title = title,
|
||||||
MessageIcon = icon,
|
MessageIcon = icon
|
||||||
};
|
};
|
||||||
var result = await messageWindow.ShowDialog<MessageBoxResult>(owner);
|
var result = await messageWindow.ShowDialog<MessageBoxResult>(owner);
|
||||||
return result;
|
return result;
|
||||||
@@ -63,16 +53,17 @@ public static class MessageBox
|
|||||||
string? title = null,
|
string? title = null,
|
||||||
string? hostId = null,
|
string? hostId = null,
|
||||||
MessageBoxIcon icon = MessageBoxIcon.None,
|
MessageBoxIcon icon = MessageBoxIcon.None,
|
||||||
MessageBoxButton button = MessageBoxButton.OKCancel)
|
MessageBoxButton button = MessageBoxButton.OKCancel,
|
||||||
|
int? toplevelHashCode = null)
|
||||||
{
|
{
|
||||||
var host = OverlayDialogManager.GetHost(hostId);
|
var host = OverlayDialogManager.GetHost(hostId, toplevelHashCode);
|
||||||
if (host is null) return MessageBoxResult.None;
|
if (host is null) return MessageBoxResult.None;
|
||||||
var messageControl = new MessageBoxControl()
|
var messageControl = new MessageBoxControl
|
||||||
{
|
{
|
||||||
Content = message,
|
Content = message,
|
||||||
Title = title,
|
Title = title,
|
||||||
Buttons = button,
|
Buttons = button,
|
||||||
MessageIcon = icon,
|
MessageIcon = icon
|
||||||
};
|
};
|
||||||
host.AddModalDialog(messageControl);
|
host.AddModalDialog(messageControl);
|
||||||
var result = await messageControl.ShowAsync<MessageBoxResult>();
|
var result = await messageControl.ShowAsync<MessageBoxResult>();
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ public partial class OverlayDialogHost
|
|||||||
if (layer.Modal)
|
if (layer.Modal)
|
||||||
{
|
{
|
||||||
_modalCount--;
|
_modalCount--;
|
||||||
HasModal = _modalCount > 0;
|
IsInModalStatus = _modalCount > 0;
|
||||||
if (!IsAnimationDisabled)
|
if (!IsAnimationDisabled)
|
||||||
{
|
{
|
||||||
await _maskDisappearAnimation.RunAsync(layer.Mask);
|
await _maskDisappearAnimation.RunAsync(layer.Mask);
|
||||||
@@ -170,7 +170,7 @@ public partial class OverlayDialogHost
|
|||||||
_maskAppearAnimation.RunAsync(mask);
|
_maskAppearAnimation.RunAsync(mask);
|
||||||
}
|
}
|
||||||
_modalCount++;
|
_modalCount++;
|
||||||
HasModal = _modalCount > 0;
|
IsInModalStatus = _modalCount > 0;
|
||||||
control.IsClosed = false;
|
control.IsClosed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public partial class OverlayDialogHost
|
|||||||
control.Arrange(new Rect(control.DesiredSize));
|
control.Arrange(new Rect(control.DesiredSize));
|
||||||
SetDrawerPosition(control);
|
SetDrawerPosition(control);
|
||||||
_modalCount++;
|
_modalCount++;
|
||||||
HasModal = _modalCount > 0;
|
IsInModalStatus = _modalCount > 0;
|
||||||
control.AddHandler(OverlayFeedbackElement.ClosedEvent, OnDrawerControlClosing);
|
control.AddHandler(OverlayFeedbackElement.ClosedEvent, OnDrawerControlClosing);
|
||||||
var animation = CreateAnimation(control.Bounds.Size, control.Position);
|
var animation = CreateAnimation(control.Bounds.Size, control.Position);
|
||||||
if (IsAnimationDisabled)
|
if (IsAnimationDisabled)
|
||||||
@@ -162,7 +162,7 @@ public partial class OverlayDialogHost
|
|||||||
if (layer.Mask is not null)
|
if (layer.Mask is not null)
|
||||||
{
|
{
|
||||||
_modalCount--;
|
_modalCount--;
|
||||||
HasModal = _modalCount > 0;
|
IsInModalStatus = _modalCount > 0;
|
||||||
layer.Mask.RemoveHandler(PointerPressedEvent, ClickMaskToCloseDialog);
|
layer.Mask.RemoveHandler(PointerPressedEvent, ClickMaskToCloseDialog);
|
||||||
if (!IsAnimationDisabled)
|
if (!IsAnimationDisabled)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ using Avalonia.Input;
|
|||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Ursa.Controls.OverlayShared;
|
using Ursa.Controls.OverlayShared;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
|
using Avalonia.VisualTree;
|
||||||
|
using Irihi.Avalonia.Shared.Helpers;
|
||||||
using Irihi.Avalonia.Shared.Shapes;
|
using Irihi.Avalonia.Shared.Shapes;
|
||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
@@ -33,17 +35,34 @@ public partial class OverlayDialogHost: Canvas
|
|||||||
|
|
||||||
private int _modalCount = 0;
|
private int _modalCount = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static readonly DirectProperty<OverlayDialogHost, bool> HasModalProperty = AvaloniaProperty.RegisterDirect<OverlayDialogHost, bool>(
|
public static readonly DirectProperty<OverlayDialogHost, bool> HasModalProperty = AvaloniaProperty.RegisterDirect<OverlayDialogHost, bool>(
|
||||||
nameof(HasModal), o => o.HasModal);
|
nameof(HasModal), o => o.HasModal);
|
||||||
private bool _hasModal;
|
private bool _hasModal;
|
||||||
|
[Obsolete("Use IsInModalStatus")]
|
||||||
public bool HasModal
|
public bool HasModal
|
||||||
{
|
{
|
||||||
get => _hasModal;
|
get => _hasModal;
|
||||||
private set => SetAndRaise(HasModalProperty, ref _hasModal, value);
|
private set => SetAndRaise(HasModalProperty, ref _hasModal, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static readonly AttachedProperty<bool> IsModalStatusScopeProperty =
|
||||||
|
AvaloniaProperty.RegisterAttached<OverlayDialogHost, Control, bool>("IsModalStatusScope");
|
||||||
|
|
||||||
|
public static void SetIsModalStatusScope(Control obj, bool value) => obj.SetValue(IsModalStatusScopeProperty, value);
|
||||||
|
internal static bool GetIsModalStatusScope(Control obj) => obj.GetValue(IsModalStatusScopeProperty);
|
||||||
|
|
||||||
|
public static readonly AttachedProperty<bool> IsInModalStatusProperty =
|
||||||
|
AvaloniaProperty.RegisterAttached<OverlayDialogHost, Control, bool>(nameof(IsInModalStatus));
|
||||||
|
|
||||||
|
internal static void SetIsInModalStatus(Control obj, bool value) => obj.SetValue(IsInModalStatusProperty, value);
|
||||||
|
public static bool GetIsInModalStatus(Control obj) => obj.GetValue(IsInModalStatusProperty);
|
||||||
|
|
||||||
|
public bool IsInModalStatus
|
||||||
|
{
|
||||||
|
get => GetValue(IsInModalStatusProperty);
|
||||||
|
set => SetValue(IsInModalStatusProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsAnimationDisabled { get; set; }
|
public bool IsAnimationDisabled { get; set; }
|
||||||
|
|
||||||
static OverlayDialogHost()
|
static OverlayDialogHost()
|
||||||
@@ -51,6 +70,11 @@ public partial class OverlayDialogHost: Canvas
|
|||||||
ClipToBoundsProperty.OverrideDefaultValue<OverlayDialogHost>(true);
|
ClipToBoundsProperty.OverrideDefaultValue<OverlayDialogHost>(true);
|
||||||
_maskAppearAnimation = CreateOpacityAnimation(true);
|
_maskAppearAnimation = CreateOpacityAnimation(true);
|
||||||
_maskDisappearAnimation = CreateOpacityAnimation(false);
|
_maskDisappearAnimation = CreateOpacityAnimation(false);
|
||||||
|
// This is only a temporary solution, will be removed in release candidate mode.
|
||||||
|
IsInModalStatusProperty.Changed.AddClassHandler<OverlayDialogHost, bool>((host, args) =>
|
||||||
|
{
|
||||||
|
host.HasModal = args.NewValue.Value;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Animation CreateOpacityAnimation(bool appear)
|
private static Animation CreateOpacityAnimation(bool appear)
|
||||||
@@ -116,11 +140,18 @@ public partial class OverlayDialogHost: Canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private IDisposable? _modalStatusSubscription;
|
||||||
protected sealed override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
protected sealed override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnAttachedToVisualTree(e);
|
base.OnAttachedToVisualTree(e);
|
||||||
OverlayDialogManager.RegisterHost(this, HostId);
|
var hash = TopLevel.GetTopLevel(this)?.GetHashCode();
|
||||||
|
var modalHost = this.GetVisualAncestors().OfType<Control>().FirstOrDefault(GetIsModalStatusScope);
|
||||||
|
if (modalHost is not null)
|
||||||
|
{
|
||||||
|
_modalStatusSubscription = this.GetObservable(IsInModalStatusProperty)
|
||||||
|
.Subscribe(a => OverlayDialogHost.SetIsInModalStatus(modalHost, a));
|
||||||
|
}
|
||||||
|
OverlayDialogManager.RegisterHost(this, HostId, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
@@ -129,7 +160,9 @@ public partial class OverlayDialogHost: Canvas
|
|||||||
{
|
{
|
||||||
_layers[0].Element.Close();
|
_layers[0].Element.Close();
|
||||||
}
|
}
|
||||||
OverlayDialogManager.UnregisterHost(HostId);
|
_modalStatusSubscription?.Dispose();
|
||||||
|
var hash = TopLevel.GetTopLevel(this)?.GetHashCode();
|
||||||
|
OverlayDialogManager.UnregisterHost(HostId, hash);
|
||||||
base.OnDetachedFromVisualTree(e);
|
base.OnDetachedFromVisualTree(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,41 +2,27 @@ using System.Collections.Concurrent;
|
|||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
|
internal record struct HostKey(string? Id, int? Hash);
|
||||||
|
|
||||||
internal static class OverlayDialogManager
|
internal static class OverlayDialogManager
|
||||||
{
|
{
|
||||||
private static OverlayDialogHost? _defaultHost;
|
private static readonly ConcurrentDictionary<HostKey, OverlayDialogHost> Hosts = new();
|
||||||
private static readonly ConcurrentDictionary<string, OverlayDialogHost> Hosts = new();
|
|
||||||
|
|
||||||
public static void RegisterHost(OverlayDialogHost host, string? id)
|
public static void RegisterHost(OverlayDialogHost host, string? id, int? hash)
|
||||||
{
|
{
|
||||||
if (id == null)
|
Hosts.TryAdd(new HostKey(id, hash), host);
|
||||||
{
|
|
||||||
if (_defaultHost != null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Cannot register multiple OverlayDialogHost with empty HostId");
|
|
||||||
}
|
|
||||||
_defaultHost = host;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Hosts.TryAdd(id, host);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UnregisterHost(string? id)
|
public static void UnregisterHost(string? id, int? hash)
|
||||||
{
|
{
|
||||||
if (id is null)
|
Hosts.TryRemove(new HostKey(id, hash), out _);
|
||||||
{
|
|
||||||
_defaultHost = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Hosts.TryRemove(id, out _);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OverlayDialogHost? GetHost(string? id)
|
public static OverlayDialogHost? GetHost(string? id, int? hash)
|
||||||
{
|
{
|
||||||
if (id is null)
|
HostKey? key = hash is null ? Hosts.Keys.Where(k => k.Id == id).ToArray().FirstOrDefault() : Hosts.Keys.FirstOrDefault(k => k.Id == id && k.Hash == hash);
|
||||||
{
|
if (key is null) return null;
|
||||||
return _defaultHost;
|
return Hosts.TryGetValue(key.Value, out var host) ? host : null;
|
||||||
}
|
|
||||||
return Hosts.TryGetValue(id, out var host) ? host : null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user