optimized menu style

This commit is contained in:
NaBian committed 2020-03-29 00:54:44 +08:00
1 parent b7222be265
commit aec26ea5be
5 files changed
+116 -15

No files matched your search

@@ -0,0 +1,99 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using HandyControl.Tools;
using HandyControl.Tools.Interop;
namespace HandyControl.Controls
{
public class MenuTopLineAttach
{
public static readonly DependencyProperty PopupProperty = DependencyProperty.RegisterAttached(
"Popup", typeof(Popup), typeof(MenuTopLineAttach), new PropertyMetadata(default(Popup), OnPopupChanged));
private static void OnPopupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var topLine = (FrameworkElement) d;
if (e.NewValue is Popup popup)
{
if (popup.TemplatedParent is MenuItem menuItem)
{
SetTopLine(menuItem, topLine);
menuItem.Unloaded += MenuItem_Unloaded;
}
popup.Opened += Popup_Opened;
}
}
private static void MenuItem_Unloaded(object sender, RoutedEventArgs e)
{
var menuItem = (FrameworkElement)sender;
menuItem.Unloaded -= MenuItem_Unloaded;
var topLine = GetTopLine(menuItem);
var popup = GetPopup(topLine);
if (popup != null)
{
popup.Opened -= Popup_Opened;
}
}
private static void Popup_Opened(object sender, EventArgs e)
{
var popup = (Popup) sender;
if (popup.TemplatedParent is MenuItem menuItem)
{
var topLine = GetTopLine(menuItem);
if (topLine == null) return;
topLine.HorizontalAlignment = HorizontalAlignment.Left;
topLine.Width = menuItem.ActualWidth;
topLine.Margin = new Thickness();
var positionLeftTop = menuItem.PointToScreen(new Point());
var positionRightBottom = menuItem.PointToScreen(new Point(menuItem.ActualWidth, menuItem.ActualHeight));
ScreenHelper.FindMonitorRectsFromPoint(InteropMethods.GetCursorPos(), out _, out var workAreaRect);
var panel = VisualHelper.GetParent<Panel>(topLine);
if (positionLeftTop.X < 0)
{
topLine.Margin = new Thickness(positionLeftTop.X - panel.Margin.Left, 0, 0, 0);
}
else if (positionLeftTop.X + panel.ActualWidth > workAreaRect.Right)
{
var overflowWidth = positionRightBottom.X - workAreaRect.Right;
if (overflowWidth > 0)
{
topLine.Width -= overflowWidth + panel.Margin.Right;
}
topLine.HorizontalAlignment = HorizontalAlignment.Left;
topLine.Margin = new Thickness(positionLeftTop.X + panel.ActualWidth - workAreaRect.Right + panel.Margin.Right, 0, 0, 0);
}
if (positionRightBottom.Y > workAreaRect.Bottom)
{
topLine.Width = 0;
topLine.HorizontalAlignment = HorizontalAlignment.Stretch;
topLine.Margin = new Thickness();
}
}
}
public static void SetPopup(DependencyObject element, Popup value)
=> element.SetValue(PopupProperty, value);
public static Popup GetPopup(DependencyObject element)
=> (Popup) element.GetValue(PopupProperty);
internal static readonly DependencyProperty TopLineProperty = DependencyProperty.RegisterAttached(
"TopLine", typeof(FrameworkElement), typeof(MenuTopLineAttach), new PropertyMetadata(default(FrameworkElement)));
internal static void SetTopLine(DependencyObject element, FrameworkElement value)
=> element.SetValue(TopLineProperty, value);
internal static FrameworkElement GetTopLine(DependencyObject element)
=> (FrameworkElement) element.GetValue(TopLineProperty);
}
}