Merge pull request #657 from irihitech/popconfirm
New Control: PopConfirm
This commit is contained in:
72
demo/Ursa.Demo/Pages/PopConfirmDemo.axaml
Normal file
72
demo/Ursa.Demo/Pages/PopConfirmDemo.axaml
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:u="https://irihi.tech/ursa"
|
||||||
|
xmlns:viewModels="clr-namespace:Ursa.Demo.ViewModels"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
x:DataType="viewModels:PopConfirmDemoViewModel"
|
||||||
|
x:Class="Ursa.Demo.Pages.PopConfirmDemo">
|
||||||
|
<StackPanel HorizontalAlignment="Left">
|
||||||
|
<Border Theme="{DynamicResource CardBorder}">
|
||||||
|
<u:Form>
|
||||||
|
<u:ControlClassesInput
|
||||||
|
Name="classInput"
|
||||||
|
u:FormItem.Label="Control Classes"
|
||||||
|
Width="240">
|
||||||
|
</u:ControlClassesInput>
|
||||||
|
<u:EnumSelector
|
||||||
|
Name="placement"
|
||||||
|
Width="240"
|
||||||
|
u:FormItem.Label="Popup Placement"
|
||||||
|
EnumType="{x:Type PlacementMode}"
|
||||||
|
Value="{x:Static PlacementMode.BottomEdgeAlignedLeft}" />
|
||||||
|
</u:Form>
|
||||||
|
</Border>
|
||||||
|
<TextBlock Text="Default PopConfirm" Margin="0 16" />
|
||||||
|
<u:PopConfirm PopupHeader="确定是否要保存此修改?"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
PopupContent="此修改将不可逆"
|
||||||
|
Placement="{Binding #placement.Value}"
|
||||||
|
ConfirmCommand="{Binding ConfirmCommand}"
|
||||||
|
CancelCommand="{Binding Path=CancelCommand}">
|
||||||
|
<Button Content="Hello World" />
|
||||||
|
</u:PopConfirm>
|
||||||
|
<TextBlock Text="GotFocus to open, LostFocus to close" Margin="0 16" />
|
||||||
|
<u:PopConfirm PopupHeader="确定是否要保存此修改?"
|
||||||
|
PopupContent="此修改将不可逆"
|
||||||
|
TriggerMode="Focus, Click"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Placement="{Binding #placement.Value}"
|
||||||
|
u:ControlClassesInput.Source="{Binding #classInput}"
|
||||||
|
ConfirmCommand="{Binding ConfirmCommand}"
|
||||||
|
CancelCommand="{Binding Path=CancelCommand}">
|
||||||
|
<Button Content="Hello World" />
|
||||||
|
</u:PopConfirm>
|
||||||
|
<TextBlock
|
||||||
|
Text="Non-button control as main element"
|
||||||
|
Margin="0 16" />
|
||||||
|
<u:PopConfirm PopupHeader="确定是否要保存此修改?"
|
||||||
|
PopupContent="此修改将不可逆"
|
||||||
|
TriggerMode="Click"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
u:ControlClassesInput.Source="{Binding #classInput}"
|
||||||
|
Placement="{Binding #placement.Value}"
|
||||||
|
ConfirmCommand="{Binding ConfirmCommand}"
|
||||||
|
CancelCommand="{Binding Path=CancelCommand}">
|
||||||
|
<TextBlock Text="Hello World" />
|
||||||
|
</u:PopConfirm>
|
||||||
|
<TextBlock Text="Asynchronized command support"
|
||||||
|
Margin="0 16" />
|
||||||
|
<u:PopConfirm PopupHeader="确定是否要保存此修改?"
|
||||||
|
PopupContent="此修改将不可逆"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Placement="{Binding #placement.Value}"
|
||||||
|
u:ControlClassesInput.Source="{Binding #classInput}"
|
||||||
|
ConfirmCommand="{Binding AsyncConfirmCommand}"
|
||||||
|
CancelCommand="{Binding Path=AsyncCancelCommand}">
|
||||||
|
<Button Content="Hello World" />
|
||||||
|
</u:PopConfirm>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
25
demo/Ursa.Demo/Pages/PopConfirmDemo.axaml.cs
Normal file
25
demo/Ursa.Demo/Pages/PopConfirmDemo.axaml.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Ursa.Controls;
|
||||||
|
using Ursa.Demo.ViewModels;
|
||||||
|
|
||||||
|
namespace Ursa.Demo.Pages;
|
||||||
|
|
||||||
|
public partial class PopConfirmDemo : UserControl
|
||||||
|
{
|
||||||
|
public PopConfirmDemo()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnAttachedToVisualTree(e);
|
||||||
|
if (this.DataContext is not PopConfirmDemoViewModel vm) return;
|
||||||
|
var manager = WindowToastManager.TryGetToastManager(TopLevel.GetTopLevel(this), out var m)
|
||||||
|
? m
|
||||||
|
: new WindowToastManager(TopLevel.GetTopLevel(this));
|
||||||
|
vm.ToastManager = manager;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -69,6 +69,7 @@ public partial class MainViewViewModel : ViewModelBase
|
|||||||
MenuKeys.MenuKeyNumPad => new NumPadDemoViewModel(),
|
MenuKeys.MenuKeyNumPad => new NumPadDemoViewModel(),
|
||||||
MenuKeys.MenuKeyPagination => new PaginationDemoViewModel(),
|
MenuKeys.MenuKeyPagination => new PaginationDemoViewModel(),
|
||||||
MenuKeys.MenuKeyPinCode => new PinCodeDemoViewModel(),
|
MenuKeys.MenuKeyPinCode => new PinCodeDemoViewModel(),
|
||||||
|
MenuKeys.MenuKeyPopConfirm => new PopConfirmDemoViewModel(),
|
||||||
MenuKeys.MenuKeyRangeSlider => new RangeSliderDemoViewModel(),
|
MenuKeys.MenuKeyRangeSlider => new RangeSliderDemoViewModel(),
|
||||||
MenuKeys.MenuKeyRating => new RatingDemoViewModel(),
|
MenuKeys.MenuKeyRating => new RatingDemoViewModel(),
|
||||||
MenuKeys.MenuKeyScrollToButton => new ScrollToButtonDemoViewModel(),
|
MenuKeys.MenuKeyScrollToButton => new ScrollToButtonDemoViewModel(),
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public class MenuViewModel : ViewModelBase
|
|||||||
new() { MenuHeader = "Loading", Key = MenuKeys.MenuKeyLoading, Status = "Updated" },
|
new() { MenuHeader = "Loading", Key = MenuKeys.MenuKeyLoading, Status = "Updated" },
|
||||||
new() { MenuHeader = "Message Box", Key = MenuKeys.MenuKeyMessageBox },
|
new() { MenuHeader = "Message Box", Key = MenuKeys.MenuKeyMessageBox },
|
||||||
new() { MenuHeader = "Notification", Key = MenuKeys.MenuKeyNotification },
|
new() { MenuHeader = "Notification", Key = MenuKeys.MenuKeyNotification },
|
||||||
|
new() { MenuHeader = "PopConfirm", Key = MenuKeys.MenuKeyPopConfirm },
|
||||||
new() { MenuHeader = "Toast", Key = MenuKeys.MenuKeyToast },
|
new() { MenuHeader = "Toast", Key = MenuKeys.MenuKeyToast },
|
||||||
new() { MenuHeader = "Skeleton", Key = MenuKeys.MenuKeySkeleton },
|
new() { MenuHeader = "Skeleton", Key = MenuKeys.MenuKeySkeleton },
|
||||||
}
|
}
|
||||||
@@ -135,6 +136,7 @@ public static class MenuKeys
|
|||||||
public const string MenuKeyNumPad = "NumPad";
|
public const string MenuKeyNumPad = "NumPad";
|
||||||
public const string MenuKeyPagination = "Pagination";
|
public const string MenuKeyPagination = "Pagination";
|
||||||
public const string MenuKeyPinCode = "PinCode";
|
public const string MenuKeyPinCode = "PinCode";
|
||||||
|
public const string MenuKeyPopConfirm = "PopConfirm";
|
||||||
public const string MenuKeyRangeSlider = "RangeSlider";
|
public const string MenuKeyRangeSlider = "RangeSlider";
|
||||||
public const string MenuKeyRating = "Rating";
|
public const string MenuKeyRating = "Rating";
|
||||||
public const string MenuKeyScrollToButton = "ScrollToButton";
|
public const string MenuKeyScrollToButton = "ScrollToButton";
|
||||||
|
|||||||
48
demo/Ursa.Demo/ViewModels/PopConfirmDemoViewModel.cs
Normal file
48
demo/Ursa.Demo/ViewModels/PopConfirmDemoViewModel.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using Avalonia.Controls.Notifications;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using Ursa.Controls;
|
||||||
|
|
||||||
|
namespace Ursa.Demo.ViewModels;
|
||||||
|
|
||||||
|
public class PopConfirmDemoViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
public PopConfirmDemoViewModel()
|
||||||
|
{
|
||||||
|
AsyncConfirmCommand = new AsyncRelayCommand(OnConfirmAsync);
|
||||||
|
AsyncCancelCommand = new RelayCommand(OnCancelAsync);
|
||||||
|
ConfirmCommand = new RelayCommand(OnConfirm);
|
||||||
|
CancelCommand = new RelayCommand(OnCancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal WindowToastManager? ToastManager { get; set; }
|
||||||
|
|
||||||
|
public ICommand ConfirmCommand { get; }
|
||||||
|
public ICommand CancelCommand { get; }
|
||||||
|
|
||||||
|
public ICommand AsyncConfirmCommand { get; }
|
||||||
|
public ICommand AsyncCancelCommand { get; }
|
||||||
|
|
||||||
|
private void OnCancel()
|
||||||
|
{
|
||||||
|
ToastManager?.Show(new Toast("Canceled"), NotificationType.Error, classes: ["Light"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnConfirm()
|
||||||
|
{
|
||||||
|
ToastManager?.Show(new Toast("Confirmed"), NotificationType.Success, classes: ["Light"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnConfirmAsync()
|
||||||
|
{
|
||||||
|
await Task.Delay(3000);
|
||||||
|
ToastManager?.Show(new Toast("Async Confirmed"), NotificationType.Success, classes: ["Light"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCancelAsync()
|
||||||
|
{
|
||||||
|
ToastManager?.Show(new Toast("Async Canceled"), NotificationType.Error, classes: ["Light"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
135
src/Ursa.Themes.Semi/Controls/PopConfirm.axaml
Normal file
135
src/Ursa.Themes.Semi/Controls/PopConfirm.axaml
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:u="https://irihi.tech/ursa"
|
||||||
|
xmlns:helpers="clr-namespace:Irihi.Avalonia.Shared.Helpers;assembly=Irihi.Avalonia.Shared">
|
||||||
|
<!-- Add Resources Here -->
|
||||||
|
<ControlTheme x:Key="{x:Type u:PopConfirm}"
|
||||||
|
TargetType="u:PopConfirm">
|
||||||
|
<Setter Property="Placement" Value="BottomEdgeAlignedLeft" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<ControlTemplate TargetType="u:PopConfirm">
|
||||||
|
<Panel>
|
||||||
|
<ContentPresenter
|
||||||
|
Name="PART_ContentPresenter"
|
||||||
|
Content="{TemplateBinding Content}"
|
||||||
|
ContentTemplate="{TemplateBinding ContentTemplate}" />
|
||||||
|
<Popup
|
||||||
|
IsLightDismissEnabled="True"
|
||||||
|
IsOpen="{Binding IsDropdownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
|
||||||
|
OverlayInputPassThroughElement="{Binding #PART_ContentPresenter}"
|
||||||
|
Name="{x:Static u:PopConfirm.PART_Popup}"
|
||||||
|
Placement="{TemplateBinding Placement}">
|
||||||
|
<Border
|
||||||
|
MaxWidth="{DynamicResource PopConfirmBorderMaxWidth}"
|
||||||
|
Padding="{DynamicResource PopConfirmBorderPadding}"
|
||||||
|
Margin="{DynamicResource PopConfirmBorderMargin}"
|
||||||
|
Background="{DynamicResource PopConfirmBackground}"
|
||||||
|
BorderBrush="{DynamicResource PopConfirmBorderBrush}"
|
||||||
|
BorderThickness="{DynamicResource PopConfirmBorderThickness}"
|
||||||
|
CornerRadius="{DynamicResource PopConfirmBorderCornerRadius}"
|
||||||
|
BoxShadow="{DynamicResource PopConfirmBorderBoxShadows}">
|
||||||
|
<Grid
|
||||||
|
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
|
RowDefinitions="*, Auto"
|
||||||
|
ColumnDefinitions="Auto, *, Auto">
|
||||||
|
<!-- Icon Area -->
|
||||||
|
<Panel
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{DynamicResource PopConfirmIconMargin}"
|
||||||
|
VerticalAlignment="Top">
|
||||||
|
<ContentPresenter
|
||||||
|
Content="{TemplateBinding Icon}" />
|
||||||
|
<PathIcon
|
||||||
|
Name="PART_BuildInIcon"
|
||||||
|
Theme="{DynamicResource InnerPathIcon}"
|
||||||
|
Classes="ExtraLarge"
|
||||||
|
Data="{DynamicResource BannerWarningIconGeometry}"
|
||||||
|
Foreground="{DynamicResource BannerWarningBorderBrush}"
|
||||||
|
IsVisible="{TemplateBinding Icon, Converter={x:Static ObjectConverters.IsNull}}" />
|
||||||
|
</Panel>
|
||||||
|
<StackPanel
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="1"
|
||||||
|
Spacing="8">
|
||||||
|
<ContentPresenter
|
||||||
|
Content="{TemplateBinding PopupHeader}"
|
||||||
|
ContentTemplate="{TemplateBinding PopupHeaderTemplate}"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
|
TextElement.FontSize="{DynamicResource PopConfirmTitleFontSize}"
|
||||||
|
TextElement.FontWeight="{DynamicResource PopConfirmTitleFontWeight}" />
|
||||||
|
<ContentPresenter
|
||||||
|
Content="{TemplateBinding PopupContent}"
|
||||||
|
ContentTemplate="{TemplateBinding PopupContentTemplate}"
|
||||||
|
Foreground="{DynamicResource PopConfirmContentForeground}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<Button
|
||||||
|
Name="{x:Static u:PopConfirm.PART_CloseButton}"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="2"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Theme="{DynamicResource OverlayCloseButton}"
|
||||||
|
Command="{TemplateBinding CancelCommand}"
|
||||||
|
CommandParameter="{TemplateBinding CancelCommandParameter}" />
|
||||||
|
<StackPanel
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="3"
|
||||||
|
Margin="0 25 0 0"
|
||||||
|
Spacing="8"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
HorizontalAlignment="Right">
|
||||||
|
<Button
|
||||||
|
Name="{x:Static u:PopConfirm.PART_CancelButton}"
|
||||||
|
Content="{DynamicResource STRING_MENU_DIALOG_CANCEL}"
|
||||||
|
Command="{TemplateBinding CancelCommand}"
|
||||||
|
CommandParameter="{TemplateBinding CancelCommandParameter}" />
|
||||||
|
<Button
|
||||||
|
Name="{x:Static u:PopConfirm.PART_ConfirmButton}"
|
||||||
|
Theme="{DynamicResource SolidButton}"
|
||||||
|
Content="{DynamicResource STRING_MENU_DIALOG_OK}"
|
||||||
|
Command="{TemplateBinding ConfirmCommand}"
|
||||||
|
CommandParameter="{TemplateBinding ConfirmCommandParameter}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Popup>
|
||||||
|
</Panel>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter>
|
||||||
|
|
||||||
|
<Style Selector="^ /template/ Button#PART_CancelButton">
|
||||||
|
<Setter Property="helpers:ClassHelper.Classes" Value="Tertiary" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="^ /template/ Button#PART_ConfirmButton">
|
||||||
|
<Setter Property="helpers:ClassHelper.Classes" Value="Primary" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="^.Information">
|
||||||
|
<Style Selector="^ /template/ PathIcon#PART_BuildInIcon">
|
||||||
|
<Setter Property="Data" Value="{DynamicResource BannerInformationIconGeometry}" />
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource BannerInformationBorderBrush}" />
|
||||||
|
</Style>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="^.Success">
|
||||||
|
<Style Selector="^ /template/ PathIcon#PART_BuildInIcon">
|
||||||
|
<Setter Property="Data" Value="{DynamicResource BannerSuccessIconGeometry}" />
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource BannerSuccessBorderBrush}" />
|
||||||
|
</Style>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="^.Warning">
|
||||||
|
<Style Selector="^ /template/ PathIcon#PART_BuildInIcon">
|
||||||
|
<Setter Property="Data" Value="{DynamicResource BannerWarningIconGeometry}" />
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource BannerWarningBorderBrush}" />
|
||||||
|
</Style>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="^.Error">
|
||||||
|
<Style Selector="^ /template/ PathIcon#PART_BuildInIcon">
|
||||||
|
<Setter Property="Data" Value="{DynamicResource BannerErrorIconGeometry}" />
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource BannerErrorBorderBrush}" />
|
||||||
|
</Style>
|
||||||
|
</Style>
|
||||||
|
</ControlTheme>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -36,26 +36,27 @@
|
|||||||
<ResourceInclude Source="NumPad.axaml" />
|
<ResourceInclude Source="NumPad.axaml" />
|
||||||
<ResourceInclude Source="NumberDisplayer.axaml" />
|
<ResourceInclude Source="NumberDisplayer.axaml" />
|
||||||
<ResourceInclude Source="Pagination.axaml" />
|
<ResourceInclude Source="Pagination.axaml" />
|
||||||
|
<ResourceInclude Source="PathPicker.axaml"/>
|
||||||
|
<ResourceInclude Source="PinCode.axaml" />
|
||||||
|
<ResourceInclude Source="PopConfirm.axaml" />
|
||||||
<ResourceInclude Source="RangeSlider.axaml" />
|
<ResourceInclude Source="RangeSlider.axaml" />
|
||||||
<ResourceInclude Source="Rating.axaml" />
|
<ResourceInclude Source="Rating.axaml" />
|
||||||
<ResourceInclude Source="Resizer.axaml" />
|
<ResourceInclude Source="Resizer.axaml" />
|
||||||
<ResourceInclude Source="ScrollToButton.axaml" />
|
<ResourceInclude Source="ScrollToButton.axaml" />
|
||||||
<ResourceInclude Source="SelectionList.axaml" />
|
<ResourceInclude Source="SelectionList.axaml" />
|
||||||
|
<ResourceInclude Source="Skeleton.axaml" />
|
||||||
|
<ResourceInclude Source="SplashWindow.axaml"/>
|
||||||
<ResourceInclude Source="TagInput.axaml" />
|
<ResourceInclude Source="TagInput.axaml" />
|
||||||
<ResourceInclude Source="ThemeSelector.axaml" />
|
<ResourceInclude Source="ThemeSelector.axaml" />
|
||||||
<ResourceInclude Source="TimePicker.axaml" />
|
<ResourceInclude Source="TimePicker.axaml" />
|
||||||
<ResourceInclude Source="TimeRangePicker.axaml" />
|
<ResourceInclude Source="TimeRangePicker.axaml" />
|
||||||
<ResourceInclude Source="Timeline.axaml" />
|
<ResourceInclude Source="Timeline.axaml" />
|
||||||
<ResourceInclude Source="TreeComboBox.axaml"/>
|
<ResourceInclude Source="TreeComboBox.axaml"/>
|
||||||
<ResourceInclude Source="Skeleton.axaml" />
|
|
||||||
<ResourceInclude Source="TwoTonePathIcon.axaml" />
|
<ResourceInclude Source="TwoTonePathIcon.axaml" />
|
||||||
<ResourceInclude Source="Toast.axaml" />
|
<ResourceInclude Source="Toast.axaml" />
|
||||||
<ResourceInclude Source="ToolBar.axaml" />
|
<ResourceInclude Source="ToolBar.axaml" />
|
||||||
<ResourceInclude Source="TimeBox.axaml"/>
|
<ResourceInclude Source="TimeBox.axaml"/>
|
||||||
<ResourceInclude Source="UrsaView.axaml" />
|
<ResourceInclude Source="UrsaView.axaml" />
|
||||||
<ResourceInclude Source="UrsaWindow.axaml"/>
|
<ResourceInclude Source="UrsaWindow.axaml"/>
|
||||||
<ResourceInclude Source="PinCode.axaml" />
|
|
||||||
<ResourceInclude Source="PathPicker.axaml"/>
|
|
||||||
<ResourceInclude Source="SplashWindow.axaml"/>
|
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
|||||||
6
src/Ursa.Themes.Semi/Themes/Dark/PopConfirm.axaml
Normal file
6
src/Ursa.Themes.Semi/Themes/Dark/PopConfirm.axaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<SolidColorBrush x:Key="PopConfirmBackground">#43444A</SolidColorBrush>
|
||||||
|
<SolidColorBrush x:Key="PopConfirmBorderBrush" Opacity="0.08" Color="White" />
|
||||||
|
<SolidColorBrush x:Key="PopConfirmContentForeground" Opacity="0.6" Color="#F9F9F9" />
|
||||||
|
<BoxShadows x:Key="PopConfirmBorderBoxShadows">inset 0 0 0 1 #1AFFFFFF, 0 4 14 #40000000</BoxShadows>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
<ResourceInclude Source="NavigationMenu.axaml" />
|
<ResourceInclude Source="NavigationMenu.axaml" />
|
||||||
<ResourceInclude Source="NotificationShared.axaml" />
|
<ResourceInclude Source="NotificationShared.axaml" />
|
||||||
<ResourceInclude Source="Pagination.axaml" />
|
<ResourceInclude Source="Pagination.axaml" />
|
||||||
|
<ResourceInclude Source="PopConfirm.axaml" />
|
||||||
<ResourceInclude Source="Rating.axaml" />
|
<ResourceInclude Source="Rating.axaml" />
|
||||||
<ResourceInclude Source="SelectionList.axaml" />
|
<ResourceInclude Source="SelectionList.axaml" />
|
||||||
<ResourceInclude Source="Skeleton.axaml" />
|
<ResourceInclude Source="Skeleton.axaml" />
|
||||||
|
|||||||
6
src/Ursa.Themes.Semi/Themes/Light/PopConfirm.axaml
Normal file
6
src/Ursa.Themes.Semi/Themes/Light/PopConfirm.axaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<SolidColorBrush x:Key="PopConfirmBackground">White</SolidColorBrush>
|
||||||
|
<SolidColorBrush x:Key="PopConfirmBorderBrush" Opacity="0.08" Color="#1C1F23" />
|
||||||
|
<SolidColorBrush x:Key="PopConfirmContentForeground" Opacity="0.62" Color="#1C1F23" />
|
||||||
|
<BoxShadows x:Key="PopConfirmBorderBoxShadows">0 0 1 #4A000000, 0 4 14 #1A000000</BoxShadows>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
<ResourceInclude Source="NavigationMenu.axaml" />
|
<ResourceInclude Source="NavigationMenu.axaml" />
|
||||||
<ResourceInclude Source="NotificationShared.axaml" />
|
<ResourceInclude Source="NotificationShared.axaml" />
|
||||||
<ResourceInclude Source="Pagination.axaml" />
|
<ResourceInclude Source="Pagination.axaml" />
|
||||||
|
<ResourceInclude Source="PopConfirm.axaml" />
|
||||||
<ResourceInclude Source="Rating.axaml" />
|
<ResourceInclude Source="Rating.axaml" />
|
||||||
<ResourceInclude Source="SelectionList.axaml" />
|
<ResourceInclude Source="SelectionList.axaml" />
|
||||||
<ResourceInclude Source="Skeleton.axaml" />
|
<ResourceInclude Source="Skeleton.axaml" />
|
||||||
|
|||||||
11
src/Ursa.Themes.Semi/Themes/Shared/PopConfirm.axaml
Normal file
11
src/Ursa.Themes.Semi/Themes/Shared/PopConfirm.axaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<x:Double x:Key="PopConfirmBorderMaxWidth">400</x:Double>
|
||||||
|
<Thickness x:Key="PopConfirmBorderPadding">20 24 24 24</Thickness>
|
||||||
|
<Thickness x:Key="PopConfirmBorderMargin">4</Thickness>
|
||||||
|
<Thickness x:Key="PopConfirmBorderThickness">1</Thickness>
|
||||||
|
<CornerRadius x:Key="PopConfirmBorderCornerRadius">6</CornerRadius>
|
||||||
|
<Thickness x:Key="PopConfirmIconMargin">0 0 12 0</Thickness>
|
||||||
|
<x:Double x:Key="PopConfirmTitleFontSize">16</x:Double>
|
||||||
|
<FontWeight x:Key="PopConfirmTitleFontWeight">600</FontWeight>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -16,8 +16,9 @@
|
|||||||
<ResourceInclude Source="NavigationMenu.axaml" />
|
<ResourceInclude Source="NavigationMenu.axaml" />
|
||||||
<ResourceInclude Source="Notification.axaml" />
|
<ResourceInclude Source="Notification.axaml" />
|
||||||
<ResourceInclude Source="Pagination.axaml" />
|
<ResourceInclude Source="Pagination.axaml" />
|
||||||
|
<ResourceInclude Source="PopConfirm.axaml" />
|
||||||
<ResourceInclude Source="Rating.axaml" />
|
<ResourceInclude Source="Rating.axaml" />
|
||||||
<ResourceInclude Source="Resizer.axaml"/>
|
<ResourceInclude Source="Resizer.axaml" />
|
||||||
<ResourceInclude Source="ScrollToButton.axaml" />
|
<ResourceInclude Source="ScrollToButton.axaml" />
|
||||||
<ResourceInclude Source="TagInput.axaml" />
|
<ResourceInclude Source="TagInput.axaml" />
|
||||||
<ResourceInclude Source="Skeleton.axaml" />
|
<ResourceInclude Source="Skeleton.axaml" />
|
||||||
|
|||||||
295
src/Ursa/Controls/PopConfirm/PopConfirm.cs
Normal file
295
src/Ursa/Controls/PopConfirm/PopConfirm.cs
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Metadata;
|
||||||
|
using Avalonia.Controls.Presenters;
|
||||||
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Controls.Templates;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.LogicalTree;
|
||||||
|
using Irihi.Avalonia.Shared.Helpers;
|
||||||
|
|
||||||
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
|
[PseudoClasses(PC_DropdownOpen, PC_Icon)]
|
||||||
|
public class PopConfirm : ContentControl
|
||||||
|
{
|
||||||
|
public const string PART_CloseButton = "PART_CloseButton";
|
||||||
|
public const string PART_ConfirmButton = "PART_ConfirmButton";
|
||||||
|
public const string PART_CancelButton = "PART_CancelButton";
|
||||||
|
public const string PART_Popup = "PART_Popup";
|
||||||
|
public const string PC_DropdownOpen = ":dropdownopen";
|
||||||
|
public const string PC_Icon = ":icon";
|
||||||
|
|
||||||
|
public static readonly StyledProperty<object?> PopupHeaderProperty = AvaloniaProperty.Register<PopConfirm, object?>(
|
||||||
|
nameof(PopupHeader));
|
||||||
|
|
||||||
|
public static readonly StyledProperty<IDataTemplate?> PopupHeaderTemplateProperty =
|
||||||
|
AvaloniaProperty.Register<PopConfirm, IDataTemplate?>(
|
||||||
|
nameof(PopupHeaderTemplate));
|
||||||
|
|
||||||
|
public static readonly StyledProperty<object?> PopupContentProperty =
|
||||||
|
AvaloniaProperty.Register<PopConfirm, object?>(
|
||||||
|
nameof(PopupContent));
|
||||||
|
|
||||||
|
public static readonly StyledProperty<IDataTemplate?> PopupContentTemplateProperty =
|
||||||
|
AvaloniaProperty.Register<PopConfirm, IDataTemplate?>(
|
||||||
|
nameof(PopupContentTemplate));
|
||||||
|
|
||||||
|
public static readonly StyledProperty<ICommand?> ConfirmCommandProperty =
|
||||||
|
AvaloniaProperty.Register<PopConfirm, ICommand?>(
|
||||||
|
nameof(ConfirmCommand));
|
||||||
|
|
||||||
|
public static readonly StyledProperty<ICommand?> CancelCommandProperty =
|
||||||
|
AvaloniaProperty.Register<PopConfirm, ICommand?>(
|
||||||
|
nameof(CancelCommand));
|
||||||
|
|
||||||
|
public static readonly StyledProperty<object?> ConfirmCommandParameterProperty =
|
||||||
|
AvaloniaProperty.Register<PopConfirm, object?>(
|
||||||
|
nameof(ConfirmCommandParameter));
|
||||||
|
|
||||||
|
public static readonly StyledProperty<object?> CancelCommandParameterProperty =
|
||||||
|
AvaloniaProperty.Register<PopConfirm, object?>(
|
||||||
|
nameof(CancelCommandParameter));
|
||||||
|
|
||||||
|
public static readonly StyledProperty<PopConfirmTriggerMode> TriggerModeProperty =
|
||||||
|
AvaloniaProperty.Register<PopConfirm, PopConfirmTriggerMode>(
|
||||||
|
nameof(TriggerMode), PopConfirmTriggerMode.Click);
|
||||||
|
|
||||||
|
public static readonly StyledProperty<bool> HandleAsyncCommandProperty =
|
||||||
|
AvaloniaProperty.Register<PopConfirm, bool>(
|
||||||
|
nameof(HandleAsyncCommand), true);
|
||||||
|
|
||||||
|
public static readonly StyledProperty<bool> IsDropdownOpenProperty = AvaloniaProperty.Register<PopConfirm, bool>(
|
||||||
|
nameof(IsDropdownOpen));
|
||||||
|
|
||||||
|
public static readonly StyledProperty<PlacementMode> PlacementProperty =
|
||||||
|
Popup.PlacementProperty.AddOwner<PopConfirm>(new StyledPropertyMetadata<PlacementMode>());
|
||||||
|
|
||||||
|
public static readonly StyledProperty<object?> IconProperty = Banner.IconProperty.AddOwner<PopConfirm>();
|
||||||
|
|
||||||
|
private Button? _closeButton;
|
||||||
|
private Button? _cancelButton;
|
||||||
|
|
||||||
|
|
||||||
|
private IDisposable? _childChangeDisposable;
|
||||||
|
|
||||||
|
private Button? _confirmButton;
|
||||||
|
private Popup? _popup;
|
||||||
|
|
||||||
|
static PopConfirm()
|
||||||
|
{
|
||||||
|
IsDropdownOpenProperty.AffectsPseudoClass<PopConfirm>(PC_DropdownOpen);
|
||||||
|
TriggerModeProperty.Changed.AddClassHandler<PopConfirm, PopConfirmTriggerMode>((pop, args) =>
|
||||||
|
pop.OnTriggerModeChanged(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? Icon
|
||||||
|
{
|
||||||
|
get => GetValue(IconProperty);
|
||||||
|
set => SetValue(IconProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? PopupHeader
|
||||||
|
{
|
||||||
|
get => GetValue(PopupHeaderProperty);
|
||||||
|
set => SetValue(PopupHeaderProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDataTemplate? PopupHeaderTemplate
|
||||||
|
{
|
||||||
|
get => GetValue(PopupHeaderTemplateProperty);
|
||||||
|
set => SetValue(PopupHeaderTemplateProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? PopupContent
|
||||||
|
{
|
||||||
|
get => GetValue(PopupContentProperty);
|
||||||
|
set => SetValue(PopupContentProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDataTemplate? PopupContentTemplate
|
||||||
|
{
|
||||||
|
get => GetValue(PopupContentTemplateProperty);
|
||||||
|
set => SetValue(PopupContentTemplateProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICommand? ConfirmCommand
|
||||||
|
{
|
||||||
|
get => GetValue(ConfirmCommandProperty);
|
||||||
|
set => SetValue(ConfirmCommandProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICommand? CancelCommand
|
||||||
|
{
|
||||||
|
get => GetValue(CancelCommandProperty);
|
||||||
|
set => SetValue(CancelCommandProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? ConfirmCommandParameter
|
||||||
|
{
|
||||||
|
get => GetValue(ConfirmCommandParameterProperty);
|
||||||
|
set => SetValue(ConfirmCommandParameterProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? CancelCommandParameter
|
||||||
|
{
|
||||||
|
get => GetValue(CancelCommandParameterProperty);
|
||||||
|
set => SetValue(CancelCommandParameterProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PopConfirmTriggerMode TriggerMode
|
||||||
|
{
|
||||||
|
get => GetValue(TriggerModeProperty);
|
||||||
|
set => SetValue(TriggerModeProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HandleAsyncCommand
|
||||||
|
{
|
||||||
|
get => GetValue(HandleAsyncCommandProperty);
|
||||||
|
set => SetValue(HandleAsyncCommandProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDropdownOpen
|
||||||
|
{
|
||||||
|
get => GetValue(IsDropdownOpenProperty);
|
||||||
|
set => SetValue(IsDropdownOpenProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlacementMode Placement
|
||||||
|
{
|
||||||
|
get => GetValue(PlacementProperty);
|
||||||
|
set => SetValue(PlacementProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTriggerModeChanged(AvaloniaPropertyChangedEventArgs<PopConfirmTriggerMode> args)
|
||||||
|
{
|
||||||
|
var child = Presenter?.Child;
|
||||||
|
TeardownChildrenEventSubscriptions(child);
|
||||||
|
SetupChildrenEventSubscriptions(child, args.GetNewValue<PopConfirmTriggerMode>());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnApplyTemplate(e);
|
||||||
|
_closeButton = e.NameScope.Find<Button>(PART_CloseButton);
|
||||||
|
_confirmButton = e.NameScope.Find<Button>(PART_ConfirmButton);
|
||||||
|
_cancelButton = e.NameScope.Find<Button>(PART_CancelButton);
|
||||||
|
_popup = e.NameScope.Find<Popup>(PART_Popup);
|
||||||
|
Button.ClickEvent.AddHandler(OnButtonClicked, _closeButton, _cancelButton, _confirmButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnButtonClicked(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!HandleAsyncCommand) _popup?.SetValue(Popup.IsOpenProperty, false);
|
||||||
|
// This is a hack for MVVM toolkit and Prism that uses INotifyPropertyChanged for async command. It counts the number of
|
||||||
|
// IsRunning property changes to determine when the command is finished.
|
||||||
|
if (sender is Button { Command: { } command and (INotifyPropertyChanged or IDisposable) } button)
|
||||||
|
{
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
void OnCanExecuteChanged(object? _, System.EventArgs a)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
if (count < 2) return;
|
||||||
|
var canExecute = command.CanExecute(button.CommandParameter);
|
||||||
|
if (canExecute)
|
||||||
|
{
|
||||||
|
_popup?.SetValue(Popup.IsOpenProperty, false);
|
||||||
|
}
|
||||||
|
command.CanExecuteChanged -= OnCanExecuteChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
command.CanExecuteChanged += OnCanExecuteChanged;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_popup?.SetValue(Popup.IsOpenProperty, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool RegisterContentPresenter(ContentPresenter presenter)
|
||||||
|
{
|
||||||
|
var result = base.RegisterContentPresenter(presenter);
|
||||||
|
if (result)
|
||||||
|
_childChangeDisposable = presenter.GetPropertyChangedObservable(ContentPresenter.ChildProperty)
|
||||||
|
.Subscribe(OnChildChanged);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnChildChanged(AvaloniaPropertyChangedEventArgs arg)
|
||||||
|
{
|
||||||
|
TeardownChildrenEventSubscriptions(arg.GetOldValue<Control?>());
|
||||||
|
SetupChildrenEventSubscriptions(arg.GetNewValue<Control?>(), TriggerMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupChildrenEventSubscriptions(Control? child, PopConfirmTriggerMode mode)
|
||||||
|
{
|
||||||
|
if (child is null) return;
|
||||||
|
if (mode.HasFlag(PopConfirmTriggerMode.Click))
|
||||||
|
{
|
||||||
|
if (child is Button button)
|
||||||
|
Button.ClickEvent.AddHandler(OnMainButtonClicked, button);
|
||||||
|
else
|
||||||
|
PointerPressedEvent.AddHandler(OnMainElementPressed, child);
|
||||||
|
}
|
||||||
|
if (mode.HasFlag(PopConfirmTriggerMode.Focus))
|
||||||
|
{
|
||||||
|
GotFocusEvent.AddHandler(OnMainElementGotFocus, child);
|
||||||
|
LostFocusEvent.AddHandler(OnMainElementLostFocus, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMainElementLostFocus(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var newFocus = TopLevel.GetTopLevel(this)?.FocusManager?.GetFocusedElement();
|
||||||
|
if (newFocus is Visual v && _popup?.IsInsidePopup(v) == true) return;
|
||||||
|
SetCurrentValue(IsDropdownOpenProperty, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _suppressButtonClickEvent;
|
||||||
|
private void OnMainElementGotFocus(object sender, GotFocusEventArgs e)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Got Focus");
|
||||||
|
if (TriggerMode.HasFlag(PopConfirmTriggerMode.Click) && TriggerMode.HasFlag(PopConfirmTriggerMode.Focus))
|
||||||
|
{
|
||||||
|
_suppressButtonClickEvent = true;
|
||||||
|
}
|
||||||
|
SetCurrentValue(IsDropdownOpenProperty, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TeardownChildrenEventSubscriptions(Control? child)
|
||||||
|
{
|
||||||
|
if (child is null) return;
|
||||||
|
PointerPressedEvent.RemoveHandler(OnMainElementPressed, child);
|
||||||
|
Button.ClickEvent.RemoveHandler(OnMainButtonClicked, child);
|
||||||
|
GotFocusEvent.RemoveHandler(OnMainElementGotFocus, child);
|
||||||
|
LostFocusEvent.RemoveHandler(OnMainElementLostFocus, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMainButtonClicked(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Main Button Clicked");
|
||||||
|
if (!_suppressButtonClickEvent)
|
||||||
|
{
|
||||||
|
SetCurrentValue(IsDropdownOpenProperty, !IsDropdownOpen);
|
||||||
|
}
|
||||||
|
_suppressButtonClickEvent = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OnMainElementPressed(object sender, PointerPressedEventArgs e)
|
||||||
|
{
|
||||||
|
SetCurrentValue(IsDropdownOpenProperty, !IsDropdownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
|
||||||
|
{
|
||||||
|
_childChangeDisposable?.Dispose();
|
||||||
|
base.OnDetachedFromLogicalTree(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/Ursa/Controls/PopConfirm/PopConfirmTriggerMode.cs
Normal file
8
src/Ursa/Controls/PopConfirm/PopConfirmTriggerMode.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum PopConfirmTriggerMode
|
||||||
|
{
|
||||||
|
Click = 1,
|
||||||
|
Focus = 2,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user