feat: implement multi layer dialog.
This commit is contained in:
@@ -7,10 +7,11 @@
|
|||||||
x:CompileBindings="True"
|
x:CompileBindings="True"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Ursa.Demo.Dialogs.DialogWithAction">
|
x:Class="Ursa.Demo.Dialogs.DialogWithAction">
|
||||||
<StackPanel Margin="0 16 0 0">
|
<StackPanel Margin="8">
|
||||||
<TextBlock Text="{Binding Title}"></TextBlock>
|
<TextBlock Classes="Strong" Margin="8" Text="{Binding Title}"></TextBlock>
|
||||||
<Calendar SelectedDate="{Binding Date}" ></Calendar>
|
<Calendar SelectedDate="{Binding Date}" ></Calendar>
|
||||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal" Spacing="20">
|
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal" Spacing="8">
|
||||||
|
<Button Content="Dialog" Command="{Binding DialogCommand}"></Button>
|
||||||
<Button Content="OK" Command="{Binding OKCommand}"></Button>
|
<Button Content="OK" Command="{Binding OKCommand}"></Button>
|
||||||
<Button Content="Cancel" Command="{Binding CancelCommand}"></Button>
|
<Button Content="Cancel" Command="{Binding CancelCommand}"></Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
@@ -16,10 +17,13 @@ public partial class DialogWithActionViewModel: ObservableObject, IDialogContext
|
|||||||
public ICommand OKCommand { get; set; }
|
public ICommand OKCommand { get; set; }
|
||||||
public ICommand CancelCommand { get; set; }
|
public ICommand CancelCommand { get; set; }
|
||||||
|
|
||||||
|
public ICommand DialogCommand { get; set; }
|
||||||
|
|
||||||
public DialogWithActionViewModel()
|
public DialogWithActionViewModel()
|
||||||
{
|
{
|
||||||
OKCommand = new RelayCommand(OK);
|
OKCommand = new RelayCommand(OK);
|
||||||
CancelCommand = new RelayCommand(Cancel);
|
CancelCommand = new RelayCommand(Cancel);
|
||||||
|
DialogCommand = new AsyncRelayCommand(ShowDialog);
|
||||||
Title = "Please select a date";
|
Title = "Please select a date";
|
||||||
Date = DateTime.Now;
|
Date = DateTime.Now;
|
||||||
}
|
}
|
||||||
@@ -33,4 +37,9 @@ public partial class DialogWithActionViewModel: ObservableObject, IDialogContext
|
|||||||
{
|
{
|
||||||
Closed?.Invoke(this, false);
|
Closed?.Invoke(this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ShowDialog()
|
||||||
|
{
|
||||||
|
await DialogBox.ShowOverlayModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(new DialogWithActionViewModel(), "GlobalHost");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -21,15 +21,16 @@
|
|||||||
<Run Text="Date: "></Run>
|
<Run Text="Date: "></Run>
|
||||||
<Run Text="{Binding DialogViewModel.Date}"></Run>
|
<Run Text="{Binding DialogViewModel.Date}"></Run>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<Button Command="{Binding ShowGlobalDialogCommand}">Show Dialog</Button>
|
<Button Command="{Binding ShowGlobalModalDialogCommand}">Show Modal Dialog</Button>
|
||||||
<Button Command="{Binding ShowLocalOverlayDialogCommand}">Show Local Overlay Dialog</Button>
|
<Button Command="{Binding ShowLocalOverlayModalDialogCommand}">Show Local Overlay Modal Dialog</Button>
|
||||||
<Button Command="{Binding ShowGlobalOverlayDialogCommand}"> Show Global Overlay Dialog </Button>
|
<Button Command="{Binding ShowGlobalOverlayModalDialogCommand}"> Show Global Overlay Modal Dialog </Button>
|
||||||
|
<Button Command="{Binding ShowGlobalOverlayDialogCommand}">Show Global Overlay Dialog</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Grid Grid.Column="1">
|
<Grid Grid.Column="1">
|
||||||
<Button
|
<Button
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Command="{Binding ShowLocalOverlayDialogCommand}">
|
Command="{Binding ShowLocalOverlayModalDialogCommand}">
|
||||||
Show Local Overlay Dialog
|
Show Local Overlay Dialog
|
||||||
</Button>
|
</Button>
|
||||||
<u:OverlayDialogHost HostId="LocalHost" />
|
<u:OverlayDialogHost HostId="LocalHost" />
|
||||||
|
|||||||
@@ -11,9 +11,11 @@ namespace Ursa.Demo.ViewModels;
|
|||||||
|
|
||||||
public class DialogDemoViewModel: ObservableObject
|
public class DialogDemoViewModel: ObservableObject
|
||||||
{
|
{
|
||||||
public ICommand ShowLocalOverlayDialogCommand { get; }
|
public ICommand ShowLocalOverlayModalDialogCommand { get; }
|
||||||
|
public ICommand ShowGlobalOverlayModalDialogCommand { get; }
|
||||||
|
public ICommand ShowGlobalModalDialogCommand { get; }
|
||||||
|
|
||||||
public ICommand ShowGlobalOverlayDialogCommand { get; }
|
public ICommand ShowGlobalOverlayDialogCommand { get; }
|
||||||
public ICommand ShowGlobalDialogCommand { get; }
|
|
||||||
|
|
||||||
private object? _result;
|
private object? _result;
|
||||||
|
|
||||||
@@ -35,27 +37,33 @@ public class DialogDemoViewModel: ObservableObject
|
|||||||
|
|
||||||
public DialogDemoViewModel()
|
public DialogDemoViewModel()
|
||||||
{
|
{
|
||||||
ShowLocalOverlayDialogCommand = new AsyncRelayCommand(ShowLocalOverlayDialog);
|
ShowLocalOverlayModalDialogCommand = new AsyncRelayCommand(ShowLocalOverlayModalDialog);
|
||||||
ShowGlobalOverlayDialogCommand = new AsyncRelayCommand(ShowGlobalOverlayDialog);
|
ShowGlobalOverlayModalDialogCommand = new AsyncRelayCommand(ShowGlobalOverlayModalDialog);
|
||||||
ShowGlobalDialogCommand = new AsyncRelayCommand(ShowGlobalDialog);
|
ShowGlobalModalDialogCommand = new AsyncRelayCommand(ShowGlobalModalDialog);
|
||||||
|
ShowGlobalOverlayDialogCommand = new RelayCommand(ShowGlobalOverlayDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ShowGlobalDialog()
|
private void ShowGlobalOverlayDialog()
|
||||||
{
|
{
|
||||||
var result = await DialogBox.ShowAsync<DialogWithAction, DialogWithActionViewModel, bool>(DialogViewModel);
|
DialogBox.ShowOverlay<DialogWithAction, DialogWithActionViewModel>(new DialogWithActionViewModel(), "GlobalHost");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ShowGlobalModalDialog()
|
||||||
|
{
|
||||||
|
var result = await DialogBox.ShowModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(DialogViewModel);
|
||||||
Result = result;
|
Result = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ShowGlobalOverlayDialog()
|
private async Task ShowGlobalOverlayModalDialog()
|
||||||
{
|
{
|
||||||
Result = await DialogBox.ShowOverlayAsync<DialogWithAction, DialogWithActionViewModel, bool>(DialogViewModel, "GlobalHost");
|
Result = await DialogBox.ShowOverlayModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(DialogViewModel, "GlobalHost");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ShowLocalOverlayDialog()
|
private async Task ShowLocalOverlayModalDialog()
|
||||||
{
|
{
|
||||||
var vm = new DialogWithActionViewModel();
|
var vm = new DialogWithActionViewModel();
|
||||||
var result = await DialogBox.ShowOverlayAsync<DialogWithAction, DialogWithActionViewModel, bool>(
|
var result = await DialogBox.ShowOverlayModalAsync<DialogWithAction, DialogWithActionViewModel, bool>(
|
||||||
DialogViewModel, "LocalHost");
|
DialogViewModel, "LocalHost", new DialogOptions(){ ExtendToClientArea = true });
|
||||||
Result = result;
|
Result = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,38 +3,58 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:u="https://irihi.tech/ursa">
|
xmlns:u="https://irihi.tech/ursa">
|
||||||
<!-- Add Resources Here -->
|
<!-- Add Resources Here -->
|
||||||
|
<ControlTheme x:Key="{x:Type u:OverlayDialogHost}" TargetType="u:OverlayDialogHost">
|
||||||
|
<Setter Property="OverlayMaskBrush" Value="{DynamicResource OverlayDialogMaskBrush}"></Setter>
|
||||||
|
</ControlTheme>
|
||||||
<ControlTheme x:Key="{x:Type u:DialogControl}" TargetType="u:DialogControl">
|
<ControlTheme x:Key="{x:Type u:DialogControl}" TargetType="u:DialogControl">
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<ControlTemplate TargetType="u:DialogControl">
|
<ControlTemplate TargetType="u:DialogControl">
|
||||||
<Border
|
<Border
|
||||||
|
Padding="0"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Classes="Hover"
|
|
||||||
IsHitTestVisible="True"
|
IsHitTestVisible="True"
|
||||||
Padding="2"
|
|
||||||
Theme="{DynamicResource CardBorder}">
|
Theme="{DynamicResource CardBorder}">
|
||||||
<Grid RowDefinitions="Auto, *, Auto">
|
<Grid RowDefinitions="Auto, *, Auto">
|
||||||
<DockPanel
|
<ContentPresenter
|
||||||
Name="{x:Static u:DialogControl.PART_TitleArea}"
|
Name="PART_ContentPresenter"
|
||||||
Grid.Row="0"
|
Grid.Row="1"
|
||||||
LastChildFill="False"
|
Content="{TemplateBinding Content}" />
|
||||||
Background="Transparent">
|
<Grid Grid.Row="0" ColumnDefinitions="*, Auto">
|
||||||
<TextBlock DockPanel.Dock="Left" Text="Title" Margin="8 8 0 0" />
|
<Panel
|
||||||
|
Name="{x:Static u:DialogControl.PART_TitleArea}"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Background="Transparent" >
|
||||||
|
<Panel.ContextFlyout>
|
||||||
|
<MenuFlyout>
|
||||||
|
<MenuItem Header="Bring to Top"></MenuItem>
|
||||||
|
</MenuFlyout>
|
||||||
|
</Panel.ContextFlyout>
|
||||||
|
</Panel>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="8,8,0,0"
|
||||||
|
DockPanel.Dock="Left"
|
||||||
|
Text="{TemplateBinding Title}"
|
||||||
|
Classes="Strong"
|
||||||
|
IsVisible="{TemplateBinding Title, Converter={x:Static ObjectConverters.IsNotNull}}"
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
Name="{x:Static u:MessageBoxWindow.PART_CloseButton}"
|
Name="{x:Static u:MessageBoxWindow.PART_CloseButton}"
|
||||||
DockPanel.Dock="Right"
|
Grid.Column="1"
|
||||||
Margin="0,4,4,0"
|
Margin="0,4,4,0"
|
||||||
Theme="{DynamicResource CloseButton}">
|
DockPanel.Dock="Right"
|
||||||
</Button>
|
Theme="{DynamicResource CloseButton}" />
|
||||||
</DockPanel>
|
</Grid>
|
||||||
<ContentPresenter
|
|
||||||
Grid.Row="0"
|
|
||||||
Grid.RowSpan="3"
|
|
||||||
Content="{TemplateBinding Content}" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter>
|
</Setter>
|
||||||
|
<Style Selector="^:extend /template/ ContentPresenter#PART_ContentPresenter">
|
||||||
|
<Setter Property="Grid.Row" Value="0" />
|
||||||
|
<Setter Property="Grid.RowSpan" Value="3" />
|
||||||
|
</Style>
|
||||||
</ControlTheme>
|
</ControlTheme>
|
||||||
|
|
||||||
<ControlTheme x:Key="{x:Type u:DialogWindow}" TargetType="u:DialogWindow">
|
<ControlTheme x:Key="{x:Type u:DialogWindow}" TargetType="u:DialogWindow">
|
||||||
@@ -69,16 +89,17 @@
|
|||||||
<Panel Margin="{TemplateBinding WindowDecorationMargin}" Background="Transparent" />
|
<Panel Margin="{TemplateBinding WindowDecorationMargin}" Background="Transparent" />
|
||||||
<ChromeOverlayLayer />
|
<ChromeOverlayLayer />
|
||||||
<Grid RowDefinitions="Auto, *, Auto">
|
<Grid RowDefinitions="Auto, *, Auto">
|
||||||
<Button
|
|
||||||
Name="{x:Static u:DialogWindow.PART_CloseButton}"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Top">
|
|
||||||
Close
|
|
||||||
</Button>
|
|
||||||
<ContentPresenter
|
<ContentPresenter
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.RowSpan="2"
|
Grid.RowSpan="2"
|
||||||
Content="{TemplateBinding Content}" />
|
Content="{TemplateBinding Content}" />
|
||||||
|
<Button
|
||||||
|
Name="{x:Static u:DialogWindow.PART_CloseButton}"
|
||||||
|
Grid.Row="0"
|
||||||
|
Margin="0,4,4,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Theme="{DynamicResource CloseButton}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Panel>
|
</Panel>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
|
|||||||
5
src/Ursa.Themes.Semi/Themes/Dark/Dialog.axaml
Normal file
5
src/Ursa.Themes.Semi/Themes/Dark/Dialog.axaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<!-- Add Resources Here -->
|
||||||
|
<SolidColorBrush x:Key="OverlayDialogMaskBrush" Color="#FFA7ABB0" Opacity="0.2"></SolidColorBrush>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
<MergeResourceInclude Source="Badge.axaml" />
|
<MergeResourceInclude Source="Badge.axaml" />
|
||||||
<MergeResourceInclude Source="Banner.axaml" />
|
<MergeResourceInclude Source="Banner.axaml" />
|
||||||
<MergeResourceInclude Source="ButtonGroup.axaml" />
|
<MergeResourceInclude Source="ButtonGroup.axaml" />
|
||||||
|
<MergeResourceInclude Source="Dialog.axaml" />
|
||||||
<MergeResourceInclude Source="Divider.axaml" />
|
<MergeResourceInclude Source="Divider.axaml" />
|
||||||
<MergeResourceInclude Source="DualBadge.axaml" />
|
<MergeResourceInclude Source="DualBadge.axaml" />
|
||||||
<MergeResourceInclude Source="IPv4Box.axaml" />
|
<MergeResourceInclude Source="IPv4Box.axaml" />
|
||||||
|
|||||||
5
src/Ursa.Themes.Semi/Themes/Light/Dialog.axaml
Normal file
5
src/Ursa.Themes.Semi/Themes/Light/Dialog.axaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<!-- Add Resources Here -->
|
||||||
|
<SolidColorBrush x:Key="OverlayDialogMaskBrush" Color="#FF555B61" Opacity="0.2"></SolidColorBrush>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
<MergeResourceInclude Source="Badge.axaml" />
|
<MergeResourceInclude Source="Badge.axaml" />
|
||||||
<MergeResourceInclude Source="Banner.axaml" />
|
<MergeResourceInclude Source="Banner.axaml" />
|
||||||
<MergeResourceInclude Source="ButtonGroup.axaml" />
|
<MergeResourceInclude Source="ButtonGroup.axaml" />
|
||||||
|
<MergeResourceInclude Source="Dialog.axaml" />
|
||||||
<MergeResourceInclude Source="Divider.axaml" />
|
<MergeResourceInclude Source="Divider.axaml" />
|
||||||
<MergeResourceInclude Source="DualBadge.axaml" />
|
<MergeResourceInclude Source="DualBadge.axaml" />
|
||||||
<MergeResourceInclude Source="IPv4Box.axaml" />
|
<MergeResourceInclude Source="IPv4Box.axaml" />
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
namespace Ursa.Common;
|
|
||||||
|
|
||||||
public enum DialogIcon
|
|
||||||
{
|
|
||||||
Asterisk, // Same as Information
|
|
||||||
Error,
|
|
||||||
Exclamation, // Same as Warning
|
|
||||||
Hand, // Same as Error
|
|
||||||
Information,
|
|
||||||
None,
|
|
||||||
Question,
|
|
||||||
Stop, // Same as Error
|
|
||||||
Warning,
|
|
||||||
Success,
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,7 @@ namespace Ursa.Controls;
|
|||||||
|
|
||||||
public static class DialogBox
|
public static class DialogBox
|
||||||
{
|
{
|
||||||
public static async Task<TResult?> ShowAsync<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()
|
var window = new DialogWindow()
|
||||||
@@ -37,28 +37,68 @@ public static class DialogBox
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<TResult> ShowAsync<TView, TViewModel, TResult>(Window owner, TViewModel vm) where
|
public static async Task<TResult> ShowModalAsync<TView, TViewModel, TResult>(Window owner, TViewModel vm) where
|
||||||
TView: Control, new()
|
TView: Control, new()
|
||||||
{
|
{
|
||||||
var window = new DialogWindow();
|
var window = new DialogWindow
|
||||||
window.Content = new TView();
|
{
|
||||||
window.DataContext = vm;
|
Content = new TView() { DataContext = vm },
|
||||||
|
DataContext = vm
|
||||||
|
};
|
||||||
return await window.ShowDialog<TResult>(owner);
|
return await window.ShowDialog<TResult>(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Task<TResult> ShowOverlayAsync<TView, TViewModel, TResult>(TViewModel vm, string hostId)
|
public static Task<TResult> ShowOverlayModalAsync<TView, TViewModel, TResult>(TViewModel vm, string hostId)
|
||||||
where TView : Control, new()
|
where TView : Control, new()
|
||||||
where TViewModel: new()
|
|
||||||
{
|
{
|
||||||
var t = new DialogControl()
|
var t = new DialogControl()
|
||||||
{
|
{
|
||||||
Content = new TView(){ DataContext = vm },
|
Content = new TView(){ DataContext = vm },
|
||||||
DataContext = vm,
|
DataContext = vm,
|
||||||
};
|
};
|
||||||
t.DataContext = vm;
|
|
||||||
var host = OverlayDialogManager.GetOverlayDialogHost(hostId);
|
var host = OverlayDialogManager.GetOverlayDialogHost(hostId);
|
||||||
host?.AddDialog(t);
|
host?.AddModalDialog(t);
|
||||||
return t.ShowAsync<TResult>();
|
return t.ShowAsync<TResult>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Task<TResult> ShowOverlayModalAsync<TView, TViewModel, TResult>(TViewModel vm, string hostId,
|
||||||
|
DialogOptions options)
|
||||||
|
where TView : Control, new()
|
||||||
|
{
|
||||||
|
var t = new DialogControl()
|
||||||
|
{
|
||||||
|
Content = new TView() { DataContext = vm },
|
||||||
|
DataContext = vm,
|
||||||
|
ExtendToClientArea = options.ExtendToClientArea,
|
||||||
|
Title = options.Title,
|
||||||
|
};
|
||||||
|
var host = OverlayDialogManager.GetOverlayDialogHost(hostId);
|
||||||
|
host?.AddModalDialog(t);
|
||||||
|
return t.ShowAsync<TResult>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ShowOverlay<TView, TViewModel>(TViewModel vm, string hostId)
|
||||||
|
where TView: Control, new()
|
||||||
|
{
|
||||||
|
var t = new DialogControl()
|
||||||
|
{
|
||||||
|
Content = new TView() { DataContext = vm },
|
||||||
|
DataContext = vm,
|
||||||
|
};
|
||||||
|
var host = OverlayDialogManager.GetOverlayDialogHost(hostId);
|
||||||
|
host?.AddDialog(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ShowOverlay<TView, TViewModel>(TViewModel vm, string hostId, DialogOptions options)
|
||||||
|
where TView: Control, new()
|
||||||
|
{
|
||||||
|
var t = new DialogControl()
|
||||||
|
{
|
||||||
|
Content = new TView() { DataContext = vm },
|
||||||
|
DataContext = vm,
|
||||||
|
};
|
||||||
|
var host = OverlayDialogManager.GetOverlayDialogHost(hostId);
|
||||||
|
host?.AddModalDialog(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -9,18 +9,39 @@ namespace Ursa.Controls;
|
|||||||
|
|
||||||
[TemplatePart(PART_CloseButton, typeof(Button))]
|
[TemplatePart(PART_CloseButton, typeof(Button))]
|
||||||
[TemplatePart(PART_TitleArea, typeof(Panel))]
|
[TemplatePart(PART_TitleArea, typeof(Panel))]
|
||||||
|
[PseudoClasses(PC_ExtendClientArea)]
|
||||||
public class DialogControl: ContentControl
|
public class DialogControl: ContentControl
|
||||||
{
|
{
|
||||||
public const string PART_CloseButton = "PART_CloseButton";
|
public const string PART_CloseButton = "PART_CloseButton";
|
||||||
public const string PART_TitleArea = "PART_TitleArea";
|
public const string PART_TitleArea = "PART_TitleArea";
|
||||||
|
public const string PC_ExtendClientArea = ":extend";
|
||||||
|
|
||||||
private Button? _closeButton;
|
private Button? _closeButton;
|
||||||
private Panel? _titleArea;
|
private Panel? _titleArea;
|
||||||
public event EventHandler<object?>? OnClose;
|
public event EventHandler<object?>? OnClose;
|
||||||
|
|
||||||
|
public static readonly StyledProperty<string?> TitleProperty = AvaloniaProperty.Register<DialogControl, string?>(
|
||||||
|
nameof(Title));
|
||||||
|
|
||||||
|
public string? Title
|
||||||
|
{
|
||||||
|
get => GetValue(TitleProperty);
|
||||||
|
set => SetValue(TitleProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<bool> ExtendToClientAreaProperty = AvaloniaProperty.Register<DialogControl, bool>(
|
||||||
|
nameof(ExtendToClientArea));
|
||||||
|
|
||||||
|
public bool ExtendToClientArea
|
||||||
|
{
|
||||||
|
get => GetValue(ExtendToClientAreaProperty);
|
||||||
|
set => SetValue(ExtendToClientAreaProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
static DialogControl()
|
static DialogControl()
|
||||||
{
|
{
|
||||||
DataContextProperty.Changed.AddClassHandler<DialogControl, object?>((o, e) => o.OnDataContextChange(e));
|
DataContextProperty.Changed.AddClassHandler<DialogControl, object?>((o, e) => o.OnDataContextChange(e));
|
||||||
|
ExtendToClientAreaProperty.Changed.AddClassHandler<DialogControl, bool>((o, e) => o.PseudoClasses.Set(PC_ExtendClientArea, e.NewValue.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDataContextChange(AvaloniaPropertyChangedEventArgs<object?> args)
|
private void OnDataContextChange(AvaloniaPropertyChangedEventArgs<object?> args)
|
||||||
@@ -34,7 +55,6 @@ public class DialogControl: ContentControl
|
|||||||
{
|
{
|
||||||
newContext.Closed += Close;
|
newContext.Closed += Close;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
|
using Ursa.Common;
|
||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
public record DialogOptions
|
public record DialogOptions
|
||||||
{
|
{
|
||||||
public bool ShowCloseButton { get; set; } = true;
|
public bool ShowCloseButton { get; set; } = true;
|
||||||
|
public string? Title { get; set; }
|
||||||
|
public bool ExtendToClientArea { get; set; } = false;
|
||||||
|
public DialogButton DefaultButtons { get; set; } = DialogButton.OKCancel;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Metadata;
|
using Avalonia.Controls.Metadata;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
@@ -15,21 +16,21 @@ public class DialogWindow: Window
|
|||||||
|
|
||||||
private Button? _closeButton;
|
private Button? _closeButton;
|
||||||
|
|
||||||
protected override void OnDataContextBeginUpdate()
|
static DialogWindow()
|
||||||
{
|
{
|
||||||
base.OnDataContextBeginUpdate();
|
DataContextProperty.Changed.AddClassHandler<DialogWindow, object?>((o, e) => o.OnDataContextChange(e));
|
||||||
if (DataContext is IDialogContext context)
|
|
||||||
{
|
|
||||||
context.Closed-= OnDialogClose;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDataContextEndUpdate()
|
private void OnDataContextChange(AvaloniaPropertyChangedEventArgs<object?> args)
|
||||||
{
|
{
|
||||||
base.OnDataContextEndUpdate();
|
if (args.OldValue.Value is IDialogContext oldContext)
|
||||||
if (DataContext is IDialogContext context)
|
|
||||||
{
|
{
|
||||||
context.Closed += OnDialogClose;
|
oldContext.Closed-= OnDialogClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.NewValue.Value is IDialogContext newContext)
|
||||||
|
{
|
||||||
|
newContext.Closed += OnDialogClose;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,39 +15,44 @@ public class OverlayDialogHost: Canvas
|
|||||||
{
|
{
|
||||||
private readonly List<DialogControl> _dialogs = new();
|
private readonly List<DialogControl> _dialogs = new();
|
||||||
private readonly List<DialogControl> _modalDialogs = new();
|
private readonly List<DialogControl> _modalDialogs = new();
|
||||||
|
private readonly List<Border> _masks = new();
|
||||||
|
|
||||||
public static readonly StyledProperty<string> HostIdProperty = AvaloniaProperty.Register<OverlayDialogHost, string>(
|
public string? HostId { get; set; }
|
||||||
nameof(HostId));
|
|
||||||
|
|
||||||
public string HostId
|
|
||||||
{
|
|
||||||
get => GetValue(HostIdProperty);
|
|
||||||
set => SetValue(HostIdProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Point _lastPoint;
|
private Point _lastPoint;
|
||||||
|
|
||||||
|
public static readonly StyledProperty<IBrush?> OverlayMaskBrushProperty = AvaloniaProperty.Register<OverlayDialogHost, IBrush?>(
|
||||||
|
nameof(OverlayMaskBrush));
|
||||||
|
|
||||||
|
public IBrush? OverlayMaskBrush
|
||||||
|
{
|
||||||
|
get => GetValue(OverlayMaskBrushProperty);
|
||||||
|
set => SetValue(OverlayMaskBrushProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Border CreateOverlayMask() => new()
|
||||||
|
{
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||||
|
VerticalAlignment = VerticalAlignment.Stretch,
|
||||||
|
Width = this.Bounds.Width,
|
||||||
|
Height = this.Bounds.Height,
|
||||||
|
[!BackgroundProperty] = this[!OverlayMaskBrushProperty],
|
||||||
|
IsVisible = true,
|
||||||
|
};
|
||||||
|
|
||||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnAttachedToVisualTree(e);
|
base.OnAttachedToVisualTree(e);
|
||||||
OverlayDialogManager.RegisterOverlayDialogHost(this, HostId);
|
OverlayDialogManager.RegisterOverlayDialogHost(this, HostId);
|
||||||
this.Children.Add(new Border()
|
|
||||||
{
|
|
||||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
|
||||||
VerticalAlignment = VerticalAlignment.Stretch,
|
|
||||||
Background = Brushes.Black,
|
|
||||||
Opacity = 0.3,
|
|
||||||
IsVisible = false,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSizeChanged(SizeChangedEventArgs e)
|
protected override void OnSizeChanged(SizeChangedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnSizeChanged(e);
|
base.OnSizeChanged(e);
|
||||||
if (this.Children.Count > 0)
|
for (int i = 0; i < _masks.Count; i++)
|
||||||
{
|
{
|
||||||
this.Children[0].Width = this.Bounds.Width;
|
_masks[i].Width = this.Bounds.Width;
|
||||||
this.Children[0].Height = this.Bounds.Height;
|
_masks[i].Width = this.Bounds.Height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,11 +92,8 @@ public class OverlayDialogHost: Canvas
|
|||||||
public void AddDialog(DialogControl control)
|
public void AddDialog(DialogControl control)
|
||||||
{
|
{
|
||||||
this.Children.Add(control);
|
this.Children.Add(control);
|
||||||
|
_dialogs.Add(control);
|
||||||
control.OnClose += OnDialogClose;
|
control.OnClose += OnDialogClose;
|
||||||
if (this.Children.Count > 1)
|
|
||||||
{
|
|
||||||
this.Children[0].IsVisible = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDialogClose(object sender, object? e)
|
private void OnDialogClose(object sender, object? e)
|
||||||
@@ -100,16 +102,38 @@ public class OverlayDialogHost: Canvas
|
|||||||
{
|
{
|
||||||
this.Children.Remove(control);
|
this.Children.Remove(control);
|
||||||
control.OnClose -= OnDialogClose;
|
control.OnClose -= OnDialogClose;
|
||||||
if (this.Children.Count == 1)
|
if (_dialogs.Contains(control))
|
||||||
{
|
{
|
||||||
this.Children[0].IsVisible = false;
|
_dialogs.Remove(control);
|
||||||
|
}
|
||||||
|
else if(_modalDialogs.Contains(control))
|
||||||
|
{
|
||||||
|
_modalDialogs.Remove(control);
|
||||||
|
if (_masks.Count > 0)
|
||||||
|
{
|
||||||
|
var last = _masks.Last();
|
||||||
|
this.Children.Remove(last);
|
||||||
|
_masks.Remove(last);
|
||||||
|
if (_masks.Count > 0)
|
||||||
|
{
|
||||||
|
_masks.Last().IsVisible= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddModalDialog(DialogControl control)
|
public void AddModalDialog(DialogControl control)
|
||||||
{
|
{
|
||||||
|
var mask = CreateOverlayMask();
|
||||||
|
this.Children.Add(mask);
|
||||||
this.Children.Add(control);
|
this.Children.Add(control);
|
||||||
|
_modalDialogs.Add(control);
|
||||||
|
for (int i = 0; i < _masks.Count; i++)
|
||||||
|
{
|
||||||
|
_masks[i].IsVisible = false;
|
||||||
|
}
|
||||||
|
_masks.Add(mask);
|
||||||
|
control.OnClose += OnDialogClose;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user