optimized menu style
This commit is contained in:
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);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Attach\IconElement.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Attach\IconSwitchElement.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Attach\InfoElement.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Attach\MenuTopLineAttach.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Attach\PanelElement.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Attach\PasswordBoxAttach.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\Attach\RectangleAttach.cs" />
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
xmlns:controls="clr-namespace:HandyControl.Controls">
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Basic/Effects.xaml"/>
|
||||
<ResourceDictionary Source="../../Basic/Geometries.xaml"/>
|
||||
<ResourceDictionary Source="../ScrollViewer.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
@@ -64,13 +65,13 @@
|
||||
</Border>
|
||||
<ContentPresenter x:Name="menuHeaderContainer" ContentTemplate="{TemplateBinding HeaderTemplate}" Grid.Column="1" ContentStringFormat="{TemplateBinding HeaderStringFormat}" ContentSource="Header" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
|
||||
<Popup Grid.Column="0" x:Name="PART_Popup" PlacementTarget="{Binding ElementName=templateRoot}" AllowsTransparency="True" Focusable="False" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom">
|
||||
<controls:SimplePanel>
|
||||
<controls:SimplePanel Effect="{StaticResource EffectShadow2}" Margin="8,0,8,8">
|
||||
<Border CornerRadius="0,0,2,2" x:Name="SubMenuBorder" BorderThickness="1" BorderBrush="{DynamicResource BorderBrush}" Background="{DynamicResource RegionBrush}">
|
||||
<ScrollViewer Style="{StaticResource ScrollViewerUpDown}" Margin="0,6">
|
||||
<ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.IsSharedSizeScope="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
<Border Height="1" Background="{DynamicResource RegionBrush}" VerticalAlignment="Top" BorderThickness="1,0" BorderBrush="{DynamicResource BorderBrush}" HorizontalAlignment="Left" Width="{Binding ActualWidth,ElementName=templateRoot}"/>
|
||||
<Border controls:MenuTopLineAttach.Popup="{Binding ElementName=PART_Popup}" Height="1" Background="{DynamicResource RegionBrush}" VerticalAlignment="Top" BorderThickness="1,0" BorderBrush="{DynamicResource BorderBrush}" HorizontalAlignment="Left"/>
|
||||
</controls:SimplePanel>
|
||||
</Popup>
|
||||
</Grid>
|
||||
|
||||
@@ -8,7 +8,6 @@ namespace HandyControl.Tools.Converter
|
||||
{
|
||||
public class TreeViewItemMarginConverter: IValueConverter
|
||||
{
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
var left = 0.0;
|
||||
|
||||
@@ -20,12 +20,10 @@ namespace HandyControl.Tools
|
||||
.FirstOrDefault(group => string.CompareOrdinal(groupName, group.Name) == 0);
|
||||
}
|
||||
|
||||
internal static FrameworkElement GetImplementationRoot(DependencyObject d)
|
||||
{
|
||||
return 1 == VisualTreeHelper.GetChildrenCount(d)
|
||||
internal static FrameworkElement GetImplementationRoot(DependencyObject d) =>
|
||||
1 == VisualTreeHelper.GetChildrenCount(d)
|
||||
? VisualTreeHelper.GetChild(d, 0) as FrameworkElement
|
||||
: null;
|
||||
}
|
||||
|
||||
public static T GetChild<T>(DependencyObject d) where T : DependencyObject
|
||||
{
|
||||
@@ -42,16 +40,19 @@ namespace HandyControl.Tools
|
||||
return default;
|
||||
}
|
||||
|
||||
public static IntPtr GetHandle(this Visual visual)
|
||||
{
|
||||
return (PresentationSource.FromVisual(visual) as HwndSource)?.Handle ?? IntPtr.Zero;
|
||||
}
|
||||
public static T GetParent<T>(DependencyObject d) where T : DependencyObject =>
|
||||
d switch
|
||||
{
|
||||
null => default,
|
||||
T t => t,
|
||||
Window _ => null,
|
||||
_ => GetParent<T>(VisualTreeHelper.GetParent(d))
|
||||
};
|
||||
|
||||
internal static void HitTestVisibleElements(Visual visual, HitTestResultCallback resultCallback,
|
||||
HitTestParameters parameters)
|
||||
{
|
||||
public static IntPtr GetHandle(this Visual visual) => (PresentationSource.FromVisual(visual) as HwndSource)?.Handle ?? IntPtr.Zero;
|
||||
|
||||
internal static void HitTestVisibleElements(Visual visual, HitTestResultCallback resultCallback, HitTestParameters parameters) =>
|
||||
VisualTreeHelper.HitTest(visual, ExcludeNonVisualElements, resultCallback, parameters);
|
||||
}
|
||||
|
||||
private static HitTestFilterBehavior ExcludeNonVisualElements(DependencyObject potentialHitTestTarget)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user