Browse Source

Merge pull request #8448 from pr8x/fix-button-flyout

Fix `Button.Flyout` not toggling
pull/8657/head
Max Katz 4 years ago
committed by GitHub
parent
commit
2911b37fe0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 56
      src/Avalonia.Controls/Button.cs
  2. 57
      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();
}

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

@ -12,17 +12,12 @@ 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>
public static readonly DirectProperty<FlyoutBase, bool> IsOpenProperty =
AvaloniaProperty.RegisterDirect<FlyoutBase, bool>(nameof(IsOpen),
x => x.IsOpen);
AvaloniaProperty.RegisterDirect<FlyoutBase, bool>(nameof(IsOpen),
x => x.IsOpen);
/// <summary>
/// Defines the <see cref="Target"/> property
@ -43,6 +38,14 @@ namespace Avalonia.Controls.Primitives
AvaloniaProperty.RegisterDirect<FlyoutBase, FlyoutShowMode>(nameof(ShowMode),
x => x.ShowMode, (x, v) => x.ShowMode = v);
/// <summary>
/// Defines the <see cref="OverlayInputPassThroughElement"/> property
/// </summary>
public static readonly DirectProperty<FlyoutBase, IInputElement?> OverlayInputPassThroughElementProperty =
Popup.OverlayInputPassThroughElementProperty.AddOwner<FlyoutBase>(
o => o._overlayInputPassThroughElement,
(o, v) => o._overlayInputPassThroughElement = v);
/// <summary>
/// Defines the AttachedFlyout property
/// </summary>
@ -57,6 +60,12 @@ namespace Avalonia.Controls.Primitives
private PixelRect? _enlargePopupRectScreenPixelRect;
private IDisposable? _transientDisposable;
private Action<IPopupHost?>? _popupHostChangedHandler;
private IInputElement? _overlayInputPassThroughElement;
static FlyoutBase()
{
Control.ContextFlyoutProperty.Changed.Subscribe(OnContextFlyoutPropertyChanged);
}
public FlyoutBase()
{
@ -101,11 +110,21 @@ namespace Avalonia.Controls.Primitives
private set => SetAndRaise(TargetProperty, ref _target, value);
}
/// <summary>
/// Gets or sets an element that should receive pointer input events even when underneath
/// the flyout's overlay.
/// </summary>
public IInputElement? OverlayInputPassThroughElement
{
get => _overlayInputPassThroughElement;
set => SetAndRaise(OverlayInputPassThroughElementProperty, ref _overlayInputPassThroughElement, value);
}
IPopupHost? IPopupHostProvider.PopupHost => Popup?.Host;
event Action<IPopupHost?>? IPopupHostProvider.PopupHostChanged
{
add => _popupHostChangedHandler += value;
event Action<IPopupHost?>? IPopupHostProvider.PopupHostChanged
{
add => _popupHostChangedHandler += value;
remove => _popupHostChangedHandler -= value;
}
@ -175,8 +194,9 @@ namespace Avalonia.Controls.Primitives
IsOpen = false;
Popup.IsOpen = false;
((ISetLogicalParent)Popup).SetParent(null);
// Ensure this isn't active
_transientDisposable?.Dispose();
_transientDisposable = null;
@ -231,6 +251,8 @@ namespace Avalonia.Controls.Primitives
Popup.Child = CreatePresenter();
}
Popup.OverlayInputPassThroughElement = OverlayInputPassThroughElement;
if (CancelOpening())
{
return false;
@ -356,10 +378,13 @@ 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,
//Note: This is required to prevent Button.Flyout from opening the flyout again after dismiss.
OverlayDismissEventPassThrough = false
};
popup.Opened += OnPopupOpened;
popup.Closed += OnPopupClosed;
@ -372,7 +397,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