From 4bd187d362ada2fe60b8010fb1525c47e5173bae Mon Sep 17 00:00:00 2001 From: amwx Date: Thu, 18 Mar 2021 21:28:40 -0500 Subject: [PATCH] Add MenuFlyout --- src/Avalonia.Controls/Flyouts/MenuFlyout.cs | 87 +++++++++++++++++++ .../Flyouts/MenuFlyoutPresenter.cs | 36 ++++++++ .../Accents/FluentControlResourcesDark.xaml | 5 ++ .../Accents/FluentControlResourcesLight.xaml | 5 ++ .../Controls/FluentControls.xaml | 2 + .../Controls/FlyoutPresenter.xaml | 5 ++ .../Controls/MenuFlyoutPresenter.xaml | 36 ++++++++ 7 files changed, 176 insertions(+) create mode 100644 src/Avalonia.Controls/Flyouts/MenuFlyout.cs create mode 100644 src/Avalonia.Controls/Flyouts/MenuFlyoutPresenter.cs create mode 100644 src/Avalonia.Themes.Fluent/Controls/MenuFlyoutPresenter.xaml diff --git a/src/Avalonia.Controls/Flyouts/MenuFlyout.cs b/src/Avalonia.Controls/Flyouts/MenuFlyout.cs new file mode 100644 index 0000000000..8eea5f211d --- /dev/null +++ b/src/Avalonia.Controls/Flyouts/MenuFlyout.cs @@ -0,0 +1,87 @@ +using System.Collections; +using System.Collections.Specialized; +using Avalonia.Collections; +using Avalonia.Controls.Primitives; +using Avalonia.Controls.Templates; +using Avalonia.Input; +using Avalonia.Metadata; +using Avalonia.Styling; + +#nullable enable + +namespace Avalonia.Controls +{ + public class MenuFlyout : FlyoutBase + { + public MenuFlyout() + { + _items = new AvaloniaList(); + } + + public static readonly DirectProperty ItemsProperty = + ItemsControl.ItemsProperty.AddOwner(x => x.Items, + (x, v) => x.Items = v); + + public static readonly DirectProperty ItemTemplateProperty = + AvaloniaProperty.RegisterDirect(nameof(ItemTemplate), + x => x.ItemTemplate, (x, v) => x.ItemTemplate = v); + + public Styles? FlyoutPresenterStyle + { + get + { + if (_styles == null) + { + _styles = new Styles(); + _styles.CollectionChanged += OnMenuFlyoutPresenterStyleChanged; + } + + return _styles; + } + } + + [Content] + public IEnumerable Items + { + get => _items; + set => SetAndRaise(ItemsProperty, ref _items, value); + } + + public IDataTemplate? ItemTemplate + { + get => _itemTemplate; + set => SetAndRaise(ItemTemplateProperty, ref _itemTemplate, value); + } + + private Styles? _styles; + private bool _stylesDirty = true; + private IEnumerable _items; + private IDataTemplate? _itemTemplate; + + protected override Control CreatePresenter() + { + return new MenuFlyoutPresenter + { + [!ItemsControl.ItemsProperty] = this[!ItemsProperty], + [!ItemsControl.ItemTemplateProperty] = this[!ItemTemplateProperty] + }; + } + + protected override void OnOpened() + { + if (_styles != null && _stylesDirty) + { + // Presenter for flyout generally shouldn't be public, so + // we should be ok to just reset the styles + _popup.Child.Styles.Clear(); + _popup.Child.Styles.Add(_styles); + } + base.OnOpened(); + } + + private void OnMenuFlyoutPresenterStyleChanged(object sender, NotifyCollectionChangedEventArgs e) + { + _stylesDirty = true; + } + } +} diff --git a/src/Avalonia.Controls/Flyouts/MenuFlyoutPresenter.cs b/src/Avalonia.Controls/Flyouts/MenuFlyoutPresenter.cs new file mode 100644 index 0000000000..7e59d824fa --- /dev/null +++ b/src/Avalonia.Controls/Flyouts/MenuFlyoutPresenter.cs @@ -0,0 +1,36 @@ +using Avalonia.Controls.Generators; +using Avalonia.Controls.Platform; +using Avalonia.Controls.Primitives; +using Avalonia.LogicalTree; + +namespace Avalonia.Controls +{ + public class MenuFlyoutPresenter : MenuBase + { + public MenuFlyoutPresenter() + :base(new DefaultMenuInteractionHandler(true)) + { + + } + + public override void Close() + { + // DefaultMenuInteractionHandler calls this + var host = this.FindLogicalAncestorOfType(); + if (host != null) + { + host.IsOpen = false; + } + } + + public override void Open() + { + //Ignore + } + + protected override IItemContainerGenerator CreateItemContainerGenerator() + { + return new MenuItemContainerGenerator(this); + } + } +} diff --git a/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml b/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml index abc02a6371..ae1fe42031 100644 --- a/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml +++ b/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml @@ -809,5 +809,10 @@ 1 + + + + + diff --git a/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml b/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml index 6a2a04f732..5af24f57a8 100644 --- a/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml +++ b/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml @@ -807,5 +807,10 @@ 1 + + + + + diff --git a/src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml b/src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml index 0acb8f4f6e..16e05ffdfd 100644 --- a/src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/FluentControls.xaml @@ -59,4 +59,6 @@ + + diff --git a/src/Avalonia.Themes.Fluent/Controls/FlyoutPresenter.xaml b/src/Avalonia.Themes.Fluent/Controls/FlyoutPresenter.xaml index 2be49d007b..3a8df060fa 100644 --- a/src/Avalonia.Themes.Fluent/Controls/FlyoutPresenter.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/FlyoutPresenter.xaml @@ -1,4 +1,9 @@ + + 1 + 0 + + + +