feat: add two attached properties to mark an custom element triggering drag move or close.
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Ursa.Demo.Dialogs"
|
xmlns:local="clr-namespace:Ursa.Demo.Dialogs"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:u="https://irihi.tech/ursa"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
Spacing="8">
|
Spacing="8">
|
||||||
|
<Rectangle Width="10" Height="10" Fill="Red" u:DialogControlBase.CanClose="True"></Rectangle>
|
||||||
<Button Command="{Binding DialogCommand}" Content="Dialog" />
|
<Button Command="{Binding DialogCommand}" Content="Dialog" />
|
||||||
<Button Command="{Binding OKCommand}" Content="OK" />
|
<Button Command="{Binding OKCommand}" Content="OK" />
|
||||||
<Button Command="{Binding CancelCommand}" Content="Cancel" />
|
<Button Command="{Binding CancelCommand}" Content="Cancel" />
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
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;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.LogicalTree;
|
||||||
using Irihi.Avalonia.Shared.Helpers;
|
using Irihi.Avalonia.Shared.Helpers;
|
||||||
using Ursa.Common;
|
using Ursa.Common;
|
||||||
using Ursa.Controls.OverlayShared;
|
using Ursa.Controls.OverlayShared;
|
||||||
@@ -29,17 +31,17 @@ public abstract class DialogControlBase: OverlayFeedbackElement
|
|||||||
internal double? VerticalOffsetRatio { get; set; }
|
internal double? VerticalOffsetRatio { get; set; }
|
||||||
internal bool CanClickOnMaskToClose { get; set; }
|
internal bool CanClickOnMaskToClose { get; set; }
|
||||||
internal bool CanLightDismiss { get; set; }
|
internal bool CanLightDismiss { get; set; }
|
||||||
|
internal bool CanDragMove { get; set; }
|
||||||
|
|
||||||
protected internal Button? _closeButton;
|
protected internal Button? _closeButton;
|
||||||
private Panel? _titleArea;
|
private Panel? _titleArea;
|
||||||
|
|
||||||
internal void SetAsModal(bool modal)
|
#region Layer Management
|
||||||
{
|
|
||||||
PseudoClasses.Set(PC_Modal, modal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly RoutedEvent<DialogLayerChangeEventArgs> LayerChangedEvent = RoutedEvent.Register<CustomDialogControl, DialogLayerChangeEventArgs>(
|
public static readonly RoutedEvent<DialogLayerChangeEventArgs> LayerChangedEvent =
|
||||||
|
RoutedEvent.Register<CustomDialogControl, DialogLayerChangeEventArgs>(
|
||||||
nameof(LayerChanged), RoutingStrategies.Bubble);
|
nameof(LayerChanged), RoutingStrategies.Bubble);
|
||||||
|
|
||||||
public event EventHandler<DialogLayerChangeEventArgs> LayerChanged
|
public event EventHandler<DialogLayerChangeEventArgs> LayerChanged
|
||||||
{
|
{
|
||||||
add => AddHandler(LayerChangedEvent, value);
|
add => AddHandler(LayerChangedEvent, value);
|
||||||
@@ -54,35 +56,133 @@ public abstract class DialogControlBase: OverlayFeedbackElement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region DragMove AttachedPropert
|
||||||
|
|
||||||
|
public static readonly AttachedProperty<bool> CanDragMoveProperty =
|
||||||
|
AvaloniaProperty.RegisterAttached<DialogControlBase, InputElement, bool>("CanDragMove");
|
||||||
|
|
||||||
|
public static void SetCanDragMove(InputElement obj, bool value) => obj.SetValue(CanDragMoveProperty, value);
|
||||||
|
public static bool GetCanDragMove(InputElement obj) => obj.GetValue(CanDragMoveProperty);
|
||||||
|
|
||||||
|
private static void OnCanDragMoveChanged(InputElement arg1, AvaloniaPropertyChangedEventArgs<bool> arg2)
|
||||||
|
{
|
||||||
|
if (arg2.NewValue.Value)
|
||||||
|
{
|
||||||
|
arg1.AddHandler(PointerPressedEvent, OnPointerPressed, RoutingStrategies.Bubble);
|
||||||
|
arg1.AddHandler(PointerMovedEvent, OnPointerMoved, RoutingStrategies.Bubble);
|
||||||
|
arg1.AddHandler(PointerReleasedEvent, OnPointerReleased, RoutingStrategies.Bubble);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arg1.RemoveHandler(PointerPressedEvent, OnPointerPressed);
|
||||||
|
arg1.RemoveHandler(PointerMovedEvent, OnPointerMoved);
|
||||||
|
arg1.RemoveHandler(PointerReleasedEvent, OnPointerReleased);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnPointerPressed(InputElement sender, PointerPressedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender.FindLogicalAncestorOfType<DialogControlBase>() is { } dialog)
|
||||||
|
{
|
||||||
|
e.Source = dialog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnPointerMoved(InputElement sender, PointerEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender.FindLogicalAncestorOfType<DialogControlBase>() is { } dialog)
|
||||||
|
{
|
||||||
|
e.Source = dialog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnPointerReleased(InputElement sender, PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender.FindLogicalAncestorOfType<DialogControlBase>() is { } dialog)
|
||||||
|
{
|
||||||
|
e.Source = dialog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Close AttachedProperty
|
||||||
|
|
||||||
|
public static readonly AttachedProperty<bool> CanCloseProperty =
|
||||||
|
AvaloniaProperty.RegisterAttached<DialogControlBase, InputElement, bool>("CanClose");
|
||||||
|
|
||||||
|
public static void SetCanClose(InputElement obj, bool value) => obj.SetValue(CanCloseProperty, value);
|
||||||
|
public static bool GetCanClose(InputElement obj) => obj.GetValue(CanCloseProperty);
|
||||||
|
private static void OnCanCloseChanged(InputElement arg1, AvaloniaPropertyChangedEventArgs<bool> arg2)
|
||||||
|
{
|
||||||
|
if (arg2.NewValue.Value)
|
||||||
|
{
|
||||||
|
arg1.AddHandler(PointerPressedEvent, OnPointerPressed, RoutingStrategies.Bubble);
|
||||||
|
}
|
||||||
|
void OnPointerPressed(InputElement sender, PointerPressedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender.FindLogicalAncestorOfType<DialogControlBase>() is { } dialog)
|
||||||
|
{
|
||||||
|
dialog.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
static DialogControlBase()
|
||||||
|
{
|
||||||
|
CanDragMoveProperty.Changed.AddClassHandler<InputElement, bool>(OnCanDragMoveChanged);
|
||||||
|
CanCloseProperty.Changed.AddClassHandler<InputElement, bool>(OnCanCloseChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnApplyTemplate(e);
|
base.OnApplyTemplate(e);
|
||||||
|
_titleArea = e.NameScope.Find<Panel>(PART_TitleArea);
|
||||||
|
if (CanDragMove)
|
||||||
|
{
|
||||||
_titleArea?.RemoveHandler(PointerMovedEvent, OnTitlePointerMove);
|
_titleArea?.RemoveHandler(PointerMovedEvent, OnTitlePointerMove);
|
||||||
_titleArea?.RemoveHandler(PointerPressedEvent, OnTitlePointerPressed);
|
_titleArea?.RemoveHandler(PointerPressedEvent, OnTitlePointerPressed);
|
||||||
_titleArea?.RemoveHandler(PointerReleasedEvent, OnTitlePointerRelease);
|
_titleArea?.RemoveHandler(PointerReleasedEvent, OnTitlePointerRelease);
|
||||||
_titleArea = e.NameScope.Find<Panel>(PART_TitleArea);
|
|
||||||
_titleArea?.AddHandler(PointerMovedEvent, OnTitlePointerMove, RoutingStrategies.Bubble);
|
_titleArea?.AddHandler(PointerMovedEvent, OnTitlePointerMove, RoutingStrategies.Bubble);
|
||||||
_titleArea?.AddHandler(PointerPressedEvent, OnTitlePointerPressed, RoutingStrategies.Bubble);
|
_titleArea?.AddHandler(PointerPressedEvent, OnTitlePointerPressed, RoutingStrategies.Bubble);
|
||||||
_titleArea?.AddHandler(PointerReleasedEvent, OnTitlePointerRelease, RoutingStrategies.Bubble);
|
_titleArea?.AddHandler(PointerReleasedEvent, OnTitlePointerRelease, RoutingStrategies.Bubble);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_titleArea is not null) _titleArea.IsHitTestVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
Button.ClickEvent.RemoveHandler(OnCloseButtonClick, _closeButton);
|
Button.ClickEvent.RemoveHandler(OnCloseButtonClick, _closeButton);
|
||||||
_closeButton = e.NameScope.Find<Button>(PART_CloseButton);
|
_closeButton = e.NameScope.Find<Button>(PART_CloseButton);
|
||||||
Button.ClickEvent.AddHandler(OnCloseButtonClick, _closeButton);
|
Button.ClickEvent.AddHandler(OnCloseButtonClick, _closeButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTitlePointerPressed(object sender, PointerPressedEventArgs e)
|
private void OnTitlePointerPressed(InputElement sender, PointerPressedEventArgs e)
|
||||||
{
|
{
|
||||||
e.Source = this;
|
e.Source = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTitlePointerMove(object sender, PointerEventArgs e)
|
private void OnTitlePointerMove(InputElement sender, PointerEventArgs e)
|
||||||
{
|
{
|
||||||
e.Source = this;
|
e.Source = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTitlePointerRelease(object sender, PointerReleasedEventArgs e)
|
private void OnTitlePointerRelease(InputElement sender, PointerReleasedEventArgs e)
|
||||||
{
|
{
|
||||||
e.Source = this;
|
e.Source = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCloseButtonClick(object sender, RoutedEventArgs args) => Close();
|
private void OnCloseButtonClick(object sender, RoutedEventArgs args) => Close();
|
||||||
|
|
||||||
|
internal void SetAsModal(bool modal)
|
||||||
|
{
|
||||||
|
PseudoClasses.Set(PC_Modal, modal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -26,4 +26,5 @@ public class DialogOptions
|
|||||||
public DialogButton Button { get; set; } = DialogButton.OKCancel;
|
public DialogButton Button { get; set; } = DialogButton.OKCancel;
|
||||||
|
|
||||||
public bool IsCloseButtonVisible { get; set; } = true;
|
public bool IsCloseButtonVisible { get; set; } = true;
|
||||||
|
public bool CanDragMove { get; set; } = true;
|
||||||
}
|
}
|
||||||
@@ -28,4 +28,5 @@ public class OverlayDialogOptions
|
|||||||
public bool IsCloseButtonVisible { get; set; } = true;
|
public bool IsCloseButtonVisible { get; set; } = true;
|
||||||
|
|
||||||
public bool CanLightDismiss { get; set; }
|
public bool CanLightDismiss { get; set; }
|
||||||
|
public bool CanDragMove { get; set; } = true;
|
||||||
}
|
}
|
||||||
@@ -192,6 +192,7 @@ public static class OverlayDialog
|
|||||||
control.CanClickOnMaskToClose = options.CanClickOnMaskToClose;
|
control.CanClickOnMaskToClose = options.CanClickOnMaskToClose;
|
||||||
control.IsCloseButtonVisible = options.IsCloseButtonVisible;
|
control.IsCloseButtonVisible = options.IsCloseButtonVisible;
|
||||||
control.CanLightDismiss = options.CanLightDismiss;
|
control.CanLightDismiss = options.CanLightDismiss;
|
||||||
|
control.CanDragMove = options.CanDragMove;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ConfigureDefaultDialogControl(DefaultDialogControl control, OverlayDialogOptions? options)
|
private static void ConfigureDefaultDialogControl(DefaultDialogControl control, OverlayDialogOptions? options)
|
||||||
@@ -210,6 +211,7 @@ public static class OverlayDialog
|
|||||||
control.Buttons = options.Buttons;
|
control.Buttons = options.Buttons;
|
||||||
control.Title = options.Title;
|
control.Title = options.Title;
|
||||||
control.CanLightDismiss = options.CanLightDismiss;
|
control.CanLightDismiss = options.CanLightDismiss;
|
||||||
|
control.CanDragMove = options.CanDragMove;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user