Added ContextMenu support
This commit is contained in:
@@ -6,6 +6,9 @@
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
IconSource="/Assets/Icon.ico"
|
||||
LightIconSource="/Assets/Icon-Light.ico">
|
||||
<controls:NotificationFlyout.ContextMenuItems>
|
||||
<MenuFlyoutItem Text="Close" />
|
||||
</controls:NotificationFlyout.ContextMenuItems>
|
||||
<StackPanel Margin="24">
|
||||
<ComboBox
|
||||
x:Name="Theme"
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using System.Collections.Generic;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
|
||||
namespace NotificationFlyout.Uwp.UI.Controls
|
||||
{
|
||||
internal class ContextMenuFlyoutHost : Control
|
||||
{
|
||||
private MenuFlyout _flyout;
|
||||
private Grid _root;
|
||||
|
||||
public ContextMenuFlyoutHost()
|
||||
@@ -12,23 +14,42 @@ namespace NotificationFlyout.Uwp.UI.Controls
|
||||
DefaultStyleKey = typeof(ContextMenuFlyoutHost);
|
||||
}
|
||||
|
||||
public void HideFlyout()
|
||||
{
|
||||
if (_flyout == null) return;
|
||||
_flyout.Hide();
|
||||
}
|
||||
|
||||
public void ShowFlyout()
|
||||
{
|
||||
if (_root == null) return;
|
||||
var flyout = FlyoutBase.GetAttachedFlyout(_root);
|
||||
flyout.ShowAt(_root, new FlyoutShowOptions { Placement = FlyoutPlacementMode.BottomEdgeAlignedLeft, ShowMode = FlyoutShowMode.TransientWithDismissOnPointerMoveAway });
|
||||
}
|
||||
if (_flyout == null) return;
|
||||
|
||||
public void HideFlyout()
|
||||
{
|
||||
if (_root == null) return;
|
||||
var flyout = FlyoutBase.GetAttachedFlyout(_root);
|
||||
flyout.Hide();
|
||||
_flyout.ShowAt(_root, new FlyoutShowOptions { Placement = FlyoutPlacementMode.BottomEdgeAlignedLeft, ShowMode = FlyoutShowMode.TransientWithDismissOnPointerMoveAway });
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
_root = GetTemplateChild("Root") as Grid;
|
||||
_flyout = GetTemplateChild("Flyout") as MenuFlyout;
|
||||
}
|
||||
|
||||
internal void SetMenuItems(IList<MenuFlyoutItemBase> addedItems, IList<MenuFlyoutItemBase> removedItems = null)
|
||||
{
|
||||
if (_flyout == null) return;
|
||||
|
||||
if (removedItems != null)
|
||||
{
|
||||
foreach (var item in removedItems)
|
||||
{
|
||||
_flyout.Items.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in addedItems)
|
||||
{
|
||||
_flyout.Items.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -8,9 +8,7 @@
|
||||
<ControlTemplate TargetType="controls:ContextMenuFlyoutHost">
|
||||
<Grid x:Name="Root">
|
||||
<FlyoutBase.AttachedFlyout>
|
||||
<MenuFlyout>
|
||||
<MenuFlyoutItem Text="Test" />
|
||||
</MenuFlyout>
|
||||
<MenuFlyout x:Name="Flyout" />
|
||||
</FlyoutBase.AttachedFlyout>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Markup;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
||||
@@ -37,15 +38,17 @@ namespace NotificationFlyout.Uwp.UI.Controls
|
||||
typeof(IList<MenuFlyoutItemBase>), typeof(NotificationFlyout),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
internal event EventHandler ContentChanged;
|
||||
internal event EventHandler IconSourceChanged;
|
||||
internal event EventHandler RequestedThemeChanged;
|
||||
|
||||
public NotificationFlyout()
|
||||
{
|
||||
ContextMenuItems = new ObservableCollection<MenuFlyoutItemBase>();
|
||||
(ContextMenuItems as INotifyCollectionChanged).CollectionChanged += OnContextMenuItemsChanged;
|
||||
}
|
||||
|
||||
internal event EventHandler ContentChanged;
|
||||
internal event EventHandler IconSourceChanged;
|
||||
internal event EventHandler<NotificationFlyoutMenuItemsChangedEventArgs> MenuItemsChanged;
|
||||
internal event EventHandler RequestedThemeChanged;
|
||||
|
||||
public UIElement Content
|
||||
{
|
||||
get => (UIElement)GetValue(ContentProperty);
|
||||
@@ -99,6 +102,14 @@ namespace NotificationFlyout.Uwp.UI.Controls
|
||||
ContentChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void OnContextMenuItemsChanged(object sender, NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
var addedItems = args.NewItems.Cast<MenuFlyoutItemBase>().ToList();
|
||||
var removedItems = args.NewItems.Cast<MenuFlyoutItemBase>().ToList();
|
||||
|
||||
MenuItemsChanged?.Invoke(this, new NotificationFlyoutMenuItemsChangedEventArgs(addedItems, removedItems));
|
||||
}
|
||||
|
||||
private void OnIconPropertyChanged()
|
||||
{
|
||||
IconSourceChanged?.Invoke(this, EventArgs.Empty);
|
||||
@@ -109,4 +120,17 @@ namespace NotificationFlyout.Uwp.UI.Controls
|
||||
RequestedThemeChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
internal class NotificationFlyoutMenuItemsChangedEventArgs : EventArgs
|
||||
{
|
||||
public NotificationFlyoutMenuItemsChangedEventArgs(IList<MenuFlyoutItemBase> addedItems, IList<MenuFlyoutItemBase> removedItems)
|
||||
{
|
||||
AddedItems = addedItems;
|
||||
RemovedItems = removedItems;
|
||||
}
|
||||
|
||||
public IList<MenuFlyoutItemBase> AddedItems { get; private set; }
|
||||
|
||||
public IList<MenuFlyoutItemBase> RemovedItems { get; private set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace NotificationFlyout.Uwp.UI.Controls
|
||||
_placement = placement;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(placement)) return;
|
||||
VisualStateManager.GoToState(this, placement, true);
|
||||
}
|
||||
|
||||
|
||||
+19
-8
@@ -1,4 +1,5 @@
|
||||
using System.Windows;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace NotificationFlyout.Wpf.UI.Controls
|
||||
@@ -11,12 +12,16 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
typeof(Uwp.UI.Controls.NotificationFlyout), typeof(NotificationFlyoutApplication),
|
||||
new PropertyMetadata(null, OnFlyoutPropertyChanged));
|
||||
|
||||
private readonly NotificationFlyoutXamlHostWindow _xamlHost;
|
||||
|
||||
private readonly ContextMenuXamlHost _contextMenuXamlHost;
|
||||
private readonly NotificationFlyoutXamlHost _notificationFlyoutXamlHost;
|
||||
public NotificationFlyoutApplication()
|
||||
{
|
||||
_xamlHost = new NotificationFlyoutXamlHostWindow();
|
||||
_xamlHost.Show();
|
||||
_notificationFlyoutXamlHost = new NotificationFlyoutXamlHost();
|
||||
_notificationFlyoutXamlHost.ContextMenuRequested += OnContextMenuRequested;
|
||||
_notificationFlyoutXamlHost.Show();
|
||||
|
||||
_contextMenuXamlHost = new ContextMenuXamlHost();
|
||||
_contextMenuXamlHost.Show();
|
||||
}
|
||||
|
||||
public Uwp.UI.Controls.NotificationFlyout Flyout
|
||||
@@ -27,12 +32,12 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
|
||||
public void HideFlyout()
|
||||
{
|
||||
_xamlHost.HideFlyout();
|
||||
_notificationFlyoutXamlHost.HideFlyout();
|
||||
}
|
||||
|
||||
public void ShowFlyout()
|
||||
{
|
||||
_xamlHost.ShowFlyout();
|
||||
_notificationFlyoutXamlHost.ShowFlyout();
|
||||
}
|
||||
|
||||
private static void OnFlyoutPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
||||
@@ -41,9 +46,15 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
sender?.OnFlyoutPropertyChanged();
|
||||
}
|
||||
|
||||
private void OnContextMenuRequested(object sender, EventArgs args)
|
||||
{
|
||||
_contextMenuXamlHost?.ShowContextMenuFlyout();
|
||||
}
|
||||
|
||||
private void OnFlyoutPropertyChanged()
|
||||
{
|
||||
_xamlHost.SetFlyout(Flyout);
|
||||
_notificationFlyoutXamlHost.SetFlyout(Flyout);
|
||||
_contextMenuXamlHost.SetFlyout(Flyout);
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
-4
@@ -2,23 +2,29 @@
|
||||
using NotificationFlyout.Wpf.UI.Extensions;
|
||||
using NotificationFlyout.Wpf.UI.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace NotificationFlyout.Wpf.UI.Controls
|
||||
{
|
||||
internal class ContextMenuXamlHost : XamlHostWindow<ContextMenuFlyoutHost>
|
||||
{
|
||||
private Uwp.UI.Controls.NotificationFlyout _flyout;
|
||||
|
||||
public ContextMenuXamlHost()
|
||||
{
|
||||
Topmost = true;
|
||||
}
|
||||
|
||||
protected override void OnDeactivated(EventArgs args)
|
||||
public void SetFlyout(Uwp.UI.Controls.NotificationFlyout flyout)
|
||||
{
|
||||
var flyoutHost = GetHostContent();
|
||||
if (flyoutHost != null)
|
||||
if (_flyout != null)
|
||||
{
|
||||
flyoutHost.HideFlyout();
|
||||
_flyout.MenuItemsChanged -= OnContextMenuItemsChanged;
|
||||
}
|
||||
|
||||
_flyout = flyout;
|
||||
UpdateMenuItems();
|
||||
}
|
||||
|
||||
public void ShowContextMenuFlyout()
|
||||
@@ -34,5 +40,39 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
|
||||
Activate();
|
||||
}
|
||||
|
||||
protected override void OnContentLoaded()
|
||||
{
|
||||
UpdateMenuItems();
|
||||
}
|
||||
|
||||
protected override void OnDeactivated(EventArgs args)
|
||||
{
|
||||
var flyoutHost = GetHostContent();
|
||||
if (flyoutHost != null)
|
||||
{
|
||||
flyoutHost.HideFlyout();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnContextMenuItemsChanged(object sender, NotificationFlyoutMenuItemsChangedEventArgs args)
|
||||
{
|
||||
UpdateMenuItems(args.AddedItems, args.RemovedItems);
|
||||
}
|
||||
|
||||
private void UpdateMenuItems()
|
||||
{
|
||||
if (_flyout == null) return;
|
||||
UpdateMenuItems(_flyout.ContextMenuItems);
|
||||
}
|
||||
|
||||
private void UpdateMenuItems(IList<MenuFlyoutItemBase> addedItems, IList<MenuFlyoutItemBase> removedItems = default)
|
||||
{
|
||||
var flyoutHost = GetHostContent();
|
||||
if (flyoutHost != null)
|
||||
{
|
||||
flyoutHost.SetMenuItems(addedItems, removedItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
-28
@@ -9,23 +9,17 @@ using System.Windows.Input;
|
||||
|
||||
namespace NotificationFlyout.Wpf.UI.Controls
|
||||
{
|
||||
internal class NotificationFlyoutXamlHostWindow : XamlHostWindow<NotificationFlyoutHost>
|
||||
internal class NotificationFlyoutXamlHost : XamlHostWindow<NotificationFlyoutHost>
|
||||
{
|
||||
private const string ShellTrayHandleName = "Shell_TrayWnd";
|
||||
|
||||
private ContextMenuXamlHost _contextMenuXamlHost;
|
||||
private Uwp.UI.Controls.NotificationFlyout _flyout;
|
||||
|
||||
private bool _isLoaded;
|
||||
|
||||
private NotificationIconHelper _notificationIconHelper;
|
||||
private SystemPersonalisationHelper _systemPersonalisationHelper;
|
||||
private TaskbarHelper _taskbarHelper;
|
||||
|
||||
public NotificationFlyoutXamlHostWindow()
|
||||
{
|
||||
Loaded += OnLoaded;
|
||||
}
|
||||
internal event EventHandler ContextMenuRequested;
|
||||
|
||||
public void SetFlyout(Uwp.UI.Controls.NotificationFlyout flyout)
|
||||
{
|
||||
@@ -75,6 +69,13 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnContentLoaded()
|
||||
{
|
||||
PrepareNotificationIcon();
|
||||
PrepareTaskbar();
|
||||
UpdateWindow();
|
||||
}
|
||||
|
||||
protected override void OnDeactivated(EventArgs args)
|
||||
{
|
||||
HideFlyout();
|
||||
@@ -104,20 +105,10 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
|
||||
if (args.MouseButton == MouseButton.Right)
|
||||
{
|
||||
ShowContextMenuFlyout();
|
||||
ContextMenuRequested?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs args)
|
||||
{
|
||||
PrepareNotificationIcon();
|
||||
PrepareTaskbar();
|
||||
|
||||
_isLoaded = true;
|
||||
|
||||
UpdateWindow();
|
||||
}
|
||||
|
||||
private void OnTaskbarChanged(object sender, EventArgs args)
|
||||
{
|
||||
UpdateWindow();
|
||||
@@ -130,14 +121,13 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
|
||||
private void PrepareNotificationIcon()
|
||||
{
|
||||
_contextMenuXamlHost = new ContextMenuXamlHost();
|
||||
_contextMenuXamlHost.Show();
|
||||
|
||||
_notificationIconHelper = NotificationIconHelper.Create(this);
|
||||
_notificationIconHelper.IconInvoked += OnIconInvoked;
|
||||
|
||||
_systemPersonalisationHelper = SystemPersonalisationHelper.Create(this);
|
||||
_systemPersonalisationHelper.ThemeChanged += OnThemeChanged;
|
||||
|
||||
UpdateIcons();
|
||||
}
|
||||
|
||||
private void PrepareTaskbar()
|
||||
@@ -145,10 +135,6 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
_taskbarHelper = TaskbarHelper.Create(this);
|
||||
_taskbarHelper.TaskbarChanged += OnTaskbarChanged;
|
||||
}
|
||||
private void ShowContextMenuFlyout()
|
||||
{
|
||||
_contextMenuXamlHost.ShowContextMenuFlyout();
|
||||
}
|
||||
|
||||
private void UpdateFlyoutContent()
|
||||
{
|
||||
@@ -166,7 +152,7 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
|
||||
private async void UpdateIcons()
|
||||
{
|
||||
if (!_isLoaded) return;
|
||||
if (!IsLoaded) return;
|
||||
|
||||
if (_flyout == null) return;
|
||||
|
||||
@@ -185,6 +171,7 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
_notificationIconHelper.SetIcon(icon.Handle);
|
||||
}
|
||||
|
||||
|
||||
private void UpdateRequestedTheme()
|
||||
{
|
||||
if (_flyout == null) return;
|
||||
@@ -200,7 +187,7 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
|
||||
private void UpdateWindow()
|
||||
{
|
||||
if (!_isLoaded) return;
|
||||
if (!IsLoaded) return;
|
||||
|
||||
var flyoutHost = GetHostContent();
|
||||
if (flyoutHost == null) return;
|
||||
|
||||
@@ -1,33 +1,44 @@
|
||||
using Microsoft.Toolkit.Wpf.UI.XamlHost;
|
||||
using NotificationFlyout.Wpf.UI.Extensions;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace NotificationFlyout.Wpf.UI.Controls
|
||||
{
|
||||
internal class XamlHostWindow<TXamlContent> : Window where TXamlContent : class
|
||||
internal class XamlHostWindow<TXamlContent> : Window where TXamlContent : Windows.UI.Xaml.UIElement
|
||||
{
|
||||
internal const double WindowSize = 5;
|
||||
protected new bool IsLoaded;
|
||||
private WindowsXamlHost _xamlHost;
|
||||
|
||||
public XamlHostWindow()
|
||||
{
|
||||
PrepareDefaultWindow();
|
||||
PrepareWindowsXamlHost();
|
||||
|
||||
Loaded += OnLoaded;
|
||||
ContentRendered += OnContentRendered;
|
||||
}
|
||||
|
||||
|
||||
internal TXamlContent GetHostContent()
|
||||
{
|
||||
if (_xamlHost == null) return null;
|
||||
return _xamlHost.GetUwpInternalObject() as TXamlContent;
|
||||
}
|
||||
|
||||
protected virtual void OnContentLoaded()
|
||||
{
|
||||
}
|
||||
|
||||
private void OnContentRendered(object sender, EventArgs args)
|
||||
{
|
||||
IsLoaded = true;
|
||||
OnContentLoaded();
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs args)
|
||||
{
|
||||
this.Hidden();
|
||||
this.Hidden();
|
||||
}
|
||||
|
||||
private void PrepareDefaultWindow()
|
||||
@@ -37,7 +48,7 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
WindowStyle = WindowStyle.None;
|
||||
ResizeMode = ResizeMode.NoResize;
|
||||
AllowsTransparency = true;
|
||||
Background = new SolidColorBrush(Colors.Red);
|
||||
Background = new SolidColorBrush(Colors.Transparent);
|
||||
Height = WindowSize;
|
||||
Width = WindowSize;
|
||||
}
|
||||
@@ -46,14 +57,13 @@ namespace NotificationFlyout.Wpf.UI.Controls
|
||||
{
|
||||
_xamlHost = new WindowsXamlHost
|
||||
{
|
||||
InitialTypeName = typeof(TXamlContent).FullName
|
||||
InitialTypeName = typeof(TXamlContent).FullName,
|
||||
Height = 0,
|
||||
Width = 0,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch
|
||||
};
|
||||
|
||||
_xamlHost.Height = 0;
|
||||
_xamlHost.Width = 0;
|
||||
_xamlHost.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
_xamlHost.VerticalAlignment = VerticalAlignment.Stretch;
|
||||
|
||||
Content = _xamlHost;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user