Browse Source

Merge remote-tracking branch 'origin/master' into feature/media-context-4

pull/11552/head
Max Katz 3 years ago
parent
commit
6863354272
  1. 4
      samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
  2. 37
      src/Avalonia.Base/Data/TemplateBinding.cs
  3. 4
      src/Avalonia.Base/Input/AccessKeyHandler.cs
  4. 2
      src/Avalonia.Base/Input/IMainMenu.cs
  5. 2
      src/Avalonia.Base/Reactive/SingleSubscriberObservableBase.cs
  6. 12
      src/Avalonia.Controls/ContextMenu.cs
  7. 4
      src/Avalonia.Controls/Menu.cs
  8. 28
      src/Avalonia.Controls/MenuBase.cs
  9. 4
      src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
  10. 14
      tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs

4
samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs

@ -19,8 +19,8 @@ namespace ControlCatalog.Pages
customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel);
var cancellableContextBorder = this.Get<Border>("CancellableContextBorder");
cancellableContextBorder.ContextMenu!.ContextMenuClosing += ContextFlyoutPage_Closing;
cancellableContextBorder.ContextMenu!.ContextMenuOpening += ContextFlyoutPage_Opening;
cancellableContextBorder.ContextMenu!.Closing += ContextFlyoutPage_Closing;
cancellableContextBorder.ContextMenu!.Opening += ContextFlyoutPage_Opening;
}
private ContextPageViewModel? _model;

37
src/Avalonia.Base/Data/TemplateBinding.cs

@ -3,18 +3,21 @@ using System.Globalization;
using Avalonia.Data.Converters;
using Avalonia.Reactive;
using Avalonia.Styling;
using Avalonia.Threading;
namespace Avalonia.Data
{
/// <summary>
/// A XAML binding to a property on a control's templated parent.
/// </summary>
public class TemplateBinding : SingleSubscriberObservableBase<object?>,
public class TemplateBinding : IObservable<object?>,
IBinding,
IDescription,
IAvaloniaSubject<object?>,
ISetterValue
ISetterValue,
IDisposable
{
private IObserver<object?>? _observer;
private bool _isSetterValue;
private StyledElement? _target;
private Type? _targetType;
@ -29,6 +32,28 @@ namespace Avalonia.Data
Property = property;
}
public IDisposable Subscribe(IObserver<object?> observer)
{
_ = observer ?? throw new ArgumentNullException(nameof(observer));
Dispatcher.UIThread.VerifyAccess();
if (_observer != null)
{
throw new InvalidOperationException("The observable can only be subscribed once.");
}
_observer = observer;
Subscribed();
return this;
}
public virtual void Dispose()
{
Unsubscribed();
_observer = null;
}
/// <inheritdoc/>
public InstancedBinding? Initiate(
AvaloniaObject target,
@ -111,7 +136,7 @@ namespace Avalonia.Data
/// <inheritdoc/>
void ISetterValue.Initialize(SetterBase setter) => _isSetterValue = true;
protected override void Subscribed()
private void Subscribed()
{
TemplatedParentChanged();
@ -121,7 +146,7 @@ namespace Avalonia.Data
}
}
protected override void Unsubscribed()
private void Unsubscribed()
{
if (_target?.TemplatedParent is { } templatedParent)
{
@ -147,12 +172,12 @@ namespace Avalonia.Data
value = Converter.Convert(value, _targetType ?? typeof(object), ConverterParameter, CultureInfo.CurrentCulture);
}
PublishNext(value);
_observer?.OnNext(value);
_hasProducedValue = true;
}
else if (_hasProducedValue)
{
PublishNext(AvaloniaProperty.UnsetValue);
_observer?.OnNext(AvaloniaProperty.UnsetValue);
_hasProducedValue = false;
}
}

4
src/Avalonia.Base/Input/AccessKeyHandler.cs

@ -65,14 +65,14 @@ namespace Avalonia.Input
{
if (_mainMenu != null)
{
_mainMenu.MenuClosed -= MainMenuClosed;
_mainMenu.Closed -= MainMenuClosed;
}
_mainMenu = value;
if (_mainMenu != null)
{
_mainMenu.MenuClosed += MainMenuClosed;
_mainMenu.Closed += MainMenuClosed;
}
}
}

2
src/Avalonia.Base/Input/IMainMenu.cs

@ -26,6 +26,6 @@ namespace Avalonia.Input
/// <summary>
/// Occurs when the main menu closes.
/// </summary>
event EventHandler<RoutedEventArgs>? MenuClosed;
event EventHandler<RoutedEventArgs>? Closed;
}
}

2
src/Avalonia.Base/Reactive/SingleSubscriberObservableBase.cs

@ -3,7 +3,7 @@ using Avalonia.Threading;
namespace Avalonia.Reactive
{
public abstract class SingleSubscriberObservableBase<T> : IObservable<T>, IDisposable
internal abstract class SingleSubscriberObservableBase<T> : IObservable<T>, IDisposable
{
private Exception? _error;
private IObserver<T>? _observer;

12
src/Avalonia.Controls/ContextMenu.cs

@ -196,14 +196,14 @@ namespace Avalonia.Controls
/// <see cref="P:Avalonia.Controls.ContextMenu.IsOpen" />
/// property is changing from false to true.
/// </summary>
public event CancelEventHandler? ContextMenuOpening;
public event CancelEventHandler? Opening;
/// <summary>
/// Occurs when the value of the
/// <see cref="P:Avalonia.Controls.ContextMenu.IsOpen" />
/// property is changing from true to false.
/// </summary>
public event CancelEventHandler? ContextMenuClosing;
public event CancelEventHandler? Closing;
/// <summary>
/// Called when the <see cref="Control.ContextMenu"/> property changes on a control.
@ -353,7 +353,7 @@ namespace Avalonia.Controls
RaiseEvent(new RoutedEventArgs
{
RoutedEvent = MenuOpenedEvent,
RoutedEvent = OpenedEvent,
Source = this,
});
}
@ -394,7 +394,7 @@ namespace Avalonia.Controls
RaiseEvent(new RoutedEventArgs
{
RoutedEvent = MenuClosedEvent,
RoutedEvent = ClosedEvent,
Source = this,
});
@ -446,14 +446,14 @@ namespace Avalonia.Controls
private bool CancelClosing()
{
var eventArgs = new CancelEventArgs();
ContextMenuClosing?.Invoke(this, eventArgs);
Closing?.Invoke(this, eventArgs);
return eventArgs.Cancel;
}
private bool CancelOpening()
{
var eventArgs = new CancelEventArgs();
ContextMenuOpening?.Invoke(this, eventArgs);
Opening?.Invoke(this, eventArgs);
return eventArgs.Cancel;
}
}

4
src/Avalonia.Controls/Menu.cs

@ -60,7 +60,7 @@ namespace Avalonia.Controls
RaiseEvent(new RoutedEventArgs
{
RoutedEvent = MenuClosedEvent,
RoutedEvent = ClosedEvent,
Source = this,
});
}
@ -77,7 +77,7 @@ namespace Avalonia.Controls
RaiseEvent(new RoutedEventArgs
{
RoutedEvent = MenuOpenedEvent,
RoutedEvent = OpenedEvent,
Source = this,
});
}

28
src/Avalonia.Controls/MenuBase.cs

@ -25,16 +25,16 @@ namespace Avalonia.Controls
o => o.IsOpen);
/// <summary>
/// Defines the <see cref="MenuOpened"/> event.
/// Defines the <see cref="Opened"/> event.
/// </summary>
public static readonly RoutedEvent<RoutedEventArgs> MenuOpenedEvent =
RoutedEvent.Register<MenuBase, RoutedEventArgs>(nameof(MenuOpened), RoutingStrategies.Bubble);
public static readonly RoutedEvent<RoutedEventArgs> OpenedEvent =
RoutedEvent.Register<MenuBase, RoutedEventArgs>(nameof(Opened), RoutingStrategies.Bubble);
/// <summary>
/// Defines the <see cref="MenuClosed"/> event.
/// Defines the <see cref="Closed"/> event.
/// </summary>
public static readonly RoutedEvent<RoutedEventArgs> MenuClosedEvent =
RoutedEvent.Register<MenuBase, RoutedEventArgs>(nameof(MenuClosed), RoutingStrategies.Bubble);
public static readonly RoutedEvent<RoutedEventArgs> ClosedEvent =
RoutedEvent.Register<MenuBase, RoutedEventArgs>(nameof(Closed), RoutingStrategies.Bubble);
private bool _isOpen;
@ -68,8 +68,8 @@ namespace Avalonia.Controls
/// </summary>
public bool IsOpen
{
get { return _isOpen; }
protected set { SetAndRaise(IsOpenProperty, ref _isOpen, value); }
get => _isOpen;
protected set => SetAndRaise(IsOpenProperty, ref _isOpen, value);
}
/// <inheritdoc/>
@ -105,19 +105,19 @@ namespace Avalonia.Controls
/// <summary>
/// Occurs when a <see cref="Menu"/> is opened.
/// </summary>
public event EventHandler<RoutedEventArgs>? MenuOpened
public event EventHandler<RoutedEventArgs>? Opened
{
add { AddHandler(MenuOpenedEvent, value); }
remove { RemoveHandler(MenuOpenedEvent, value); }
add => AddHandler(OpenedEvent, value);
remove => RemoveHandler(OpenedEvent, value);
}
/// <summary>
/// Occurs when a <see cref="Menu"/> is closed.
/// </summary>
public event EventHandler<RoutedEventArgs>? MenuClosed
public event EventHandler<RoutedEventArgs>? Closed
{
add { AddHandler(MenuClosedEvent, value); }
remove { RemoveHandler(MenuClosedEvent, value); }
add => AddHandler(ClosedEvent, value);
remove => RemoveHandler(ClosedEvent, value);
}
/// <summary>

4
src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs

@ -290,7 +290,7 @@ namespace Avalonia.Controls.Platform
Menu.PointerPressed += PointerPressed;
Menu.PointerReleased += PointerReleased;
Menu.AddHandler(AccessKeyHandler.AccessKeyPressedEvent, AccessKeyPressed);
Menu.AddHandler(MenuBase.MenuOpenedEvent, MenuOpened);
Menu.AddHandler(MenuBase.OpenedEvent, MenuOpened);
Menu.AddHandler(MenuItem.PointerEnteredItemEvent, PointerEntered);
Menu.AddHandler(MenuItem.PointerExitedItemEvent, PointerExited);
Menu.AddHandler(InputElement.PointerMovedEvent, PointerMoved);
@ -326,7 +326,7 @@ namespace Avalonia.Controls.Platform
Menu.PointerPressed -= PointerPressed;
Menu.PointerReleased -= PointerReleased;
Menu.RemoveHandler(AccessKeyHandler.AccessKeyPressedEvent, AccessKeyPressed);
Menu.RemoveHandler(MenuBase.MenuOpenedEvent, MenuOpened);
Menu.RemoveHandler(MenuBase.OpenedEvent, MenuOpened);
Menu.RemoveHandler(MenuItem.PointerEnteredItemEvent, PointerEntered);
Menu.RemoveHandler(MenuItem.PointerExitedItemEvent, PointerExited);
Menu.RemoveHandler(InputElement.PointerMovedEvent, PointerMoved);

14
tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs

@ -36,7 +36,7 @@ namespace Avalonia.Controls.UnitTests
int openedCount = 0;
sut.MenuOpened += (sender, args) =>
sut.Opened += (sender, args) =>
{
openedCount++;
};
@ -139,7 +139,7 @@ namespace Avalonia.Controls.UnitTests
int openedCount = 0;
sut.MenuOpened += (sender, args) =>
sut.Opened += (sender, args) =>
{
openedCount++;
};
@ -168,7 +168,7 @@ namespace Avalonia.Controls.UnitTests
bool opened = false;
sut.MenuOpened += (sender, args) =>
sut.Opened += (sender, args) =>
{
opened = true;
};
@ -221,7 +221,7 @@ namespace Avalonia.Controls.UnitTests
int closedCount = 0;
sut.MenuClosed += (sender, args) =>
sut.Closed += (sender, args) =>
{
closedCount++;
};
@ -259,7 +259,7 @@ namespace Avalonia.Controls.UnitTests
var tracker = 0;
var c = new ContextMenu();
c.ContextMenuClosing += (s, e) =>
c.Closing += (s, e) =>
{
tracker++;
e.Cancel = true;
@ -431,7 +431,7 @@ namespace Avalonia.Controls.UnitTests
};
new Window { Content = target };
sut.ContextMenuOpening += (c, e) => { eventCalled = true; e.Cancel = true; };
sut.Opening += (c, e) => { eventCalled = true; e.Cancel = true; };
_mouse.Click(target, MouseButton.Right);
@ -575,7 +575,7 @@ namespace Avalonia.Controls.UnitTests
var window = PreparedWindow(target);
var overlay = LightDismissOverlayLayer.GetLightDismissOverlayLayer(window);
sut.ContextMenuClosing += (c, e) => { eventCalled = true; e.Cancel = true; };
sut.Closing += (c, e) => { eventCalled = true; e.Cancel = true; };
window.Show();

Loading…
Cancel
Save