Browse Source

Fix button flyout toggle

Expose OverlayDismissEventPassThrough on FlyoutBase
pull/8448/head
Luis von der Eltz 4 years ago
parent
commit
9ab31f60b4
  1. 56
      src/Avalonia.Controls/Button.cs
  2. 48
      src/Avalonia.Controls/Flyouts/FlyoutBase.cs
  3. 2
      src/Avalonia.Controls/Primitives/Popup.cs

56
src/Avalonia.Controls/Button.cs

@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Windows.Input;
using Avalonia.Automation.Peers;
@ -281,24 +282,29 @@ namespace Avalonia.Controls
/// <inheritdoc/>
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Enter)
switch (e.Key)
{
OnClick();
e.Handled = true;
}
else if (e.Key == Key.Space)
{
if (ClickMode == ClickMode.Press)
{
case Key.Enter:
OnClick();
e.Handled = true;
break;
case Key.Space:
{
if (ClickMode == ClickMode.Press)
{
OnClick();
}
IsPressed = true;
e.Handled = true;
break;
}
IsPressed = true;
e.Handled = true;
}
else if (e.Key == Key.Escape && Flyout != null)
{
// If Flyout doesn't have focusable content, close the flyout here
Flyout.Hide();
case Key.Escape when Flyout != null:
// If Flyout doesn't have focusable content, close the flyout here
CloseFlyout();
break;
}
base.OnKeyDown(e);
@ -327,7 +333,14 @@ namespace Avalonia.Controls
{
if (IsEffectivelyEnabled)
{
OpenFlyout();
if (_isFlyoutOpen)
{
CloseFlyout();
}
else
{
OpenFlyout();
}
var e = new RoutedEventArgs(ClickEvent);
RaiseEvent(e);
@ -348,6 +361,14 @@ namespace Avalonia.Controls
Flyout?.ShowAt(this);
}
/// <summary>
/// Closes the button's flyout.
/// </summary>
protected virtual void CloseFlyout()
{
Flyout?.Hide();
}
/// <summary>
/// Invoked when the button's flyout is opened.
/// </summary>
@ -494,8 +515,7 @@ namespace Avalonia.Controls
// If flyout is changed while one is already open, make sure we
// close the old one first
if (oldFlyout != null &&
oldFlyout.IsOpen)
if (oldFlyout != null && oldFlyout.IsOpen)
{
oldFlyout.Hide();
}

48
src/Avalonia.Controls/Flyouts/FlyoutBase.cs

@ -12,11 +12,6 @@ namespace Avalonia.Controls.Primitives
{
public abstract class FlyoutBase : AvaloniaObject, IPopupHostProvider
{
static FlyoutBase()
{
Control.ContextFlyoutProperty.Changed.Subscribe(OnContextFlyoutPropertyChanged);
}
/// <summary>
/// Defines the <see cref="IsOpen"/> property
/// </summary>
@ -49,6 +44,12 @@ namespace Avalonia.Controls.Primitives
public static readonly AttachedProperty<FlyoutBase?> AttachedFlyoutProperty =
AvaloniaProperty.RegisterAttached<FlyoutBase, Control, FlyoutBase?>("AttachedFlyout", null);
/// <summary>
/// Defines the OverlayDismissEventPassThrough property
/// </summary>
public static readonly StyledProperty<bool> OverlayDismissEventPassThroughProperty =
Popup.OverlayDismissEventPassThroughProperty.AddOwner<FlyoutBase>();
private readonly Lazy<Popup> _popupLazy;
private bool _isOpen;
private Control? _target;
@ -58,6 +59,12 @@ namespace Avalonia.Controls.Primitives
private IDisposable? _transientDisposable;
private Action<IPopupHost?>? _popupHostChangedHandler;
static FlyoutBase()
{
OverlayDismissEventPassThroughProperty.OverrideDefaultValue<FlyoutBase>(true);
Control.ContextFlyoutProperty.Changed.Subscribe(OnContextFlyoutPropertyChanged);
}
public FlyoutBase()
{
_popupLazy = new Lazy<Popup>(() => CreatePopup());
@ -101,6 +108,21 @@ namespace Avalonia.Controls.Primitives
private set => SetAndRaise(TargetProperty, ref _target, value);
}
/// <summary>
/// Gets or sets a value indicating whether the event that closes the flyout is passed
/// through to the parent window.
/// </summary>
/// <remarks>
/// Clicks outside the the flyout cause the flyout to close. When <see cref="OverlayDismissEventPassThrough"/> is set to
/// false, these clicks will be handled by the flyout and not be registered by the parent
/// window. When set to true, the events will be passed through to the parent window.
/// </remarks>
public bool OverlayDismissEventPassThrough
{
get => GetValue(OverlayDismissEventPassThroughProperty);
set => SetValue(OverlayDismissEventPassThroughProperty, value);
}
IPopupHost? IPopupHostProvider.PopupHost => Popup?.Host;
event Action<IPopupHost?>? IPopupHostProvider.PopupHostChanged
@ -175,6 +197,8 @@ namespace Avalonia.Controls.Primitives
IsOpen = false;
Popup.IsOpen = false;
Popup.OverlayInputPassThroughElement = null;
((ISetLogicalParent)Popup).SetParent(null);
// Ensure this isn't active
@ -231,6 +255,9 @@ namespace Avalonia.Controls.Primitives
Popup.Child = CreatePresenter();
}
Popup.OverlayInputPassThroughElement = placementTarget;
Popup.OverlayDismissEventPassThrough = OverlayDismissEventPassThrough;
if (CancelOpening())
{
return false;
@ -356,10 +383,11 @@ namespace Avalonia.Controls.Primitives
private Popup CreatePopup()
{
var popup = new Popup();
popup.WindowManagerAddShadowHint = false;
popup.IsLightDismissEnabled = true;
popup.OverlayDismissEventPassThrough = true;
var popup = new Popup
{
WindowManagerAddShadowHint = false,
IsLightDismissEnabled = true
};
popup.Opened += OnPopupOpened;
popup.Closed += OnPopupClosed;
@ -372,7 +400,7 @@ namespace Avalonia.Controls.Primitives
{
IsOpen = true;
_popupHostChangedHandler?.Invoke(Popup!.Host);
_popupHostChangedHandler?.Invoke(Popup.Host);
}
private void OnPopupClosing(object? sender, CancelEventArgs e)

2
src/Avalonia.Controls/Primitives/Popup.cs

@ -501,7 +501,7 @@ namespace Avalonia.Controls.Primitives
if (dismissLayer != null)
{
dismissLayer.IsVisible = true;
dismissLayer.InputPassThroughElement = _overlayInputPassThroughElement;
dismissLayer.InputPassThroughElement = OverlayInputPassThroughElement;
Disposable.Create(() =>
{

Loading…
Cancel
Save