feat: update to finish functionality, start to build theme.
This commit is contained in:
@@ -1,42 +1,171 @@
|
||||
<ResourceDictionary
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:converters="clr-namespace:Ursa.Themes.Semi.Converters"
|
||||
xmlns:u="https://irihi.tech/ursa">
|
||||
<!-- Add Resources Here -->
|
||||
|
||||
<converters:NavigationMenuItemLevelToMarginConverter x:Key="MarginConverter" Indent="8" />
|
||||
|
||||
<ControlTheme x:Key="{x:Type u:NavigationMenu}" TargetType="u:NavigationMenu">
|
||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate TargetType="u:NavigationMenu">
|
||||
<Border Background="{TemplateBinding Background}">
|
||||
<StackPanel>
|
||||
<ContentPresenter Name="PART_HeaderPresenter" Content="Hello" />
|
||||
<ItemsPresenter ItemsPanel="{TemplateBinding ItemsPanel}" />
|
||||
</StackPanel>
|
||||
<Border
|
||||
Name="PART_RootBorder"
|
||||
Width="260"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<Border.Transitions>
|
||||
<Transitions>
|
||||
<DoubleTransition Property="Width" Duration="0:0:0.2" />
|
||||
</Transitions>
|
||||
</Border.Transitions>
|
||||
<Grid
|
||||
Name="PART_RootGrid"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="{TemplateBinding Background}"
|
||||
RowDefinitions="Auto, *, Auto, Auto">
|
||||
<StackPanel
|
||||
Margin="18"
|
||||
HorizontalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<ContentPresenter
|
||||
Name="PART_IconPresenter"
|
||||
Margin="0,8"
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding Icon}" />
|
||||
<ContentPresenter
|
||||
Name="PART_HeaderPresenter"
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding Header}"
|
||||
ContentTemplate="{TemplateBinding HeaderTemplate}"
|
||||
FontSize="18" />
|
||||
|
||||
</StackPanel>
|
||||
<ItemsPresenter Grid.Row="1" ItemsPanel="{TemplateBinding ItemsPanel}" />
|
||||
<ContentPresenter
|
||||
Name="PART_FooterPresenter"
|
||||
Grid.Row="2"
|
||||
Content="{TemplateBinding Footer}"
|
||||
ContentTemplate="{TemplateBinding FooterTemplate}" />
|
||||
<ToggleButton
|
||||
Name="{x:Static u:NavigationMenu.PART_CloseButton}"
|
||||
Grid.Row="3"
|
||||
Content="Open"
|
||||
IsChecked="{TemplateBinding IsClosed,
|
||||
Mode=TwoWay}"
|
||||
IsVisible="{TemplateBinding ShowCollapseButton}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
<Style Selector="^:closed">
|
||||
<Style Selector="^ /template/ ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="ContentPresenter.IsVisible" Value="False" />
|
||||
</Style>
|
||||
<Style Selector="^ /template/ Border#PART_RootBorder">
|
||||
<Setter Property="Border.Width" Value="60" />
|
||||
</Style>
|
||||
<Style Selector="^ /template/ ContentPresenter#PART_IconPresenter">
|
||||
<Setter Property="Grid.HorizontalAlignment" Value="Center" />
|
||||
</Style>
|
||||
</Style>
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme x:Key="{x:Type u:NavigationMenuItem}" TargetType="u:NavigationMenuItem">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate TargetType="u:NavigationMenuItem">
|
||||
<Border
|
||||
Padding="4"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="1">
|
||||
<Border>
|
||||
<StackPanel>
|
||||
<ContentPresenter
|
||||
Name="PART_HeaderPresenter"
|
||||
Background="{TemplateBinding Background}"
|
||||
Content="{TemplateBinding Header}"
|
||||
ContentTemplate="{TemplateBinding HeaderTemplate}" />
|
||||
<ItemsPresenter ItemsPanel="{TemplateBinding ItemsPanel}" />
|
||||
<Border
|
||||
Name="PART_HeaderBorder"
|
||||
Margin="0,2"
|
||||
Padding="8"
|
||||
Background="Transparent"
|
||||
CornerRadius="6">
|
||||
<Grid
|
||||
Name="PART_RootStackPanel"
|
||||
HorizontalAlignment="Stretch"
|
||||
ColumnDefinitions="Auto, Auto, *, Auto">
|
||||
<ContentPresenter
|
||||
Name="PART_IconPresenter"
|
||||
Grid.Column="1"
|
||||
MinWidth="32"
|
||||
Margin="{TemplateBinding Level,
|
||||
Converter={StaticResource MarginConverter}}"
|
||||
Content="{TemplateBinding Icon}"
|
||||
ContentTemplate="{TemplateBinding IconTemplate}" />
|
||||
<ContentPresenter
|
||||
Name="PART_HeaderPresenter"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Background="{TemplateBinding Background}"
|
||||
Content="{TemplateBinding Header}"
|
||||
ContentTemplate="{TemplateBinding HeaderTemplate}">
|
||||
<ContentPresenter.Transitions>
|
||||
<Transitions>
|
||||
<DoubleTransition Property="Opacity" Duration="0:0:0.15" />
|
||||
</Transitions>
|
||||
</ContentPresenter.Transitions>
|
||||
</ContentPresenter>
|
||||
<PathIcon
|
||||
Name="PART_ExpandIcon"
|
||||
Grid.Column="3"
|
||||
Width="8"
|
||||
Height="8"
|
||||
Data="M4.08045 7.59809C4.66624 7.01231 5.61599 7.01231 6.20177 7.59809L11.8586 13.2549L17.5155 7.59809C18.1013 7.01231 19.051 7.01231 19.6368 7.59809C20.2226 8.18388 20.2226 9.13363 19.6368 9.71941L12.9193 16.4369C12.3335 17.0227 11.3838 17.0227 10.798 16.4369L4.08045 9.71941C3.49467 9.13363 3.49467 8.18388 4.08045 7.59809Z">
|
||||
<PathIcon.Transitions>
|
||||
<Transitions>
|
||||
<TransformOperationsTransition Property="RenderTransform" Duration="0.1" />
|
||||
</Transitions>
|
||||
</PathIcon.Transitions>
|
||||
</PathIcon>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ItemsPresenter Name="PART_ItemsPresenter" ItemsPanel="{TemplateBinding ItemsPanel}">
|
||||
<ItemsPresenter.Transitions>
|
||||
<Transitions>
|
||||
<DoubleTransition Property="Height" Duration="0:0:0.15" />
|
||||
<DoubleTransition Property="Opacity" Duration="0:0:0.15" />
|
||||
</Transitions>
|
||||
</ItemsPresenter.Transitions>
|
||||
</ItemsPresenter>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
<Style Selector="^:selected">
|
||||
<Setter Property="u:NavigationMenuItem.Background" Value="Red" />
|
||||
<Style Selector="^ /template/ Border#PART_HeaderBorder:pointerover">
|
||||
<Setter Property="Border.Background" Value="LightGray" />
|
||||
</Style>
|
||||
<Style Selector="^:highlighted /template/ ContentPresenter#PART_IconPresenter">
|
||||
<Setter Property="u:NavigationMenuItem.Foreground" Value="Blue" />
|
||||
</Style>
|
||||
<Style Selector="^:selected /template/ Border#PART_HeaderBorder">
|
||||
<Setter Property="u:NavigationMenuItem.Background" Value="LightBlue" />
|
||||
</Style>
|
||||
<Style Selector="^:closed /template/ ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="ContentPresenter.Opacity" Value="0" />
|
||||
</Style>
|
||||
<Style Selector="^:closed /template/ StackPanel#PART_RootStackPanel">
|
||||
<Setter Property="StackPanel.HorizontalAlignment" Value="Center" />
|
||||
</Style>
|
||||
<Style Selector="^:closed /template/ ItemsPresenter#PART_ItemsPresenter">
|
||||
<Setter Property="ItemsPresenter.IsVisible" Value="False" />
|
||||
</Style>
|
||||
<Style Selector="^:collapsed /template/ ItemsPresenter#PART_ItemsPresenter">
|
||||
<Setter Property="ItemsPresenter.Height" Value="0" />
|
||||
<Setter Property="ItemsPresenter.Opacity" Value="0" />
|
||||
</Style>
|
||||
<Style Selector="^:not(:empty):collapsed /template/ PathIcon#PART_ExpandIcon">
|
||||
<Setter Property="PathIcon.RenderTransform" Value="rotate(180deg)" />
|
||||
</Style>
|
||||
<Style Selector="^:empty /template/ PathIcon#PART_ExpandIcon">
|
||||
<Setter Property="PathIcon.IsVisible" Value="False" />
|
||||
</Style>
|
||||
</ControlTheme>
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Globalization;
|
||||
using Avalonia;
|
||||
using Avalonia.Data.Converters;
|
||||
|
||||
namespace Ursa.Themes.Semi.Converters;
|
||||
|
||||
public class NavigationMenuItemLevelToMarginConverter: IValueConverter
|
||||
{
|
||||
public int Indent { get; set; }
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is int i)
|
||||
{
|
||||
return new Thickness((i-1) * Indent, 0, 0, 0);
|
||||
}
|
||||
return new Thickness();
|
||||
}
|
||||
|
||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Specialized;
|
||||
using Avalonia;
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
@@ -12,8 +13,14 @@ using Avalonia.Metadata;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
public class NavigationMenu: HeaderedSelectingItemsControl
|
||||
[PseudoClasses(PC_Closed)]
|
||||
[TemplatePart(Name = PART_CloseButton, Type = typeof(ToggleButton))]
|
||||
|
||||
public class NavigationMenu: HeaderedItemsControl
|
||||
{
|
||||
public const string PC_Closed = ":closed";
|
||||
public const string PART_CloseButton = "PART_CloseButton";
|
||||
|
||||
public static readonly StyledProperty<object?> FooterProperty = AvaloniaProperty.Register<NavigationMenu, object?>(
|
||||
nameof(Footer));
|
||||
|
||||
@@ -32,13 +39,82 @@ public class NavigationMenu: HeaderedSelectingItemsControl
|
||||
set => SetValue(FooterTemplateProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<object?> SelectedMenuItemProperty = AvaloniaProperty.Register<NavigationMenu, object?>(
|
||||
nameof(SelectedMenuItem));
|
||||
public static readonly StyledProperty<object?> IconProperty = AvaloniaProperty.Register<NavigationMenu, object?>(
|
||||
nameof(Icon));
|
||||
|
||||
public object? SelectedMenuItem
|
||||
public object? Icon
|
||||
{
|
||||
get => GetValue(SelectedMenuItemProperty);
|
||||
set => SetValue(SelectedMenuItemProperty, value);
|
||||
get => GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
|
||||
public static readonly StyledProperty<object?> SelectedItemProperty = AvaloniaProperty.Register<NavigationMenu, object?>(
|
||||
nameof(SelectedItem));
|
||||
|
||||
public object? SelectedItem
|
||||
{
|
||||
get => GetValue(SelectedItemProperty);
|
||||
set => SetValue(SelectedItemProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> ShowCollapseButtonProperty = AvaloniaProperty.Register<NavigationMenu, bool>(
|
||||
nameof(ShowCollapseButton));
|
||||
|
||||
public bool ShowCollapseButton
|
||||
{
|
||||
get => GetValue(ShowCollapseButtonProperty);
|
||||
set => SetValue(ShowCollapseButtonProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> IsClosedProperty = AvaloniaProperty.Register<NavigationMenu, bool>(
|
||||
nameof(IsClosed));
|
||||
|
||||
public bool IsClosed
|
||||
{
|
||||
get => GetValue(IsClosedProperty);
|
||||
set => SetValue(IsClosedProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<double> OpenedWidthProperty = AvaloniaProperty.Register<NavigationMenu, double>(
|
||||
nameof(OpenedWidth));
|
||||
|
||||
public double OpenedWidth
|
||||
{
|
||||
get => GetValue(OpenedWidthProperty);
|
||||
set => SetValue(OpenedWidthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<double> ClosedWidthProperty = AvaloniaProperty.Register<NavigationMenu, double>(
|
||||
nameof(ClosedWidth));
|
||||
|
||||
public double ClosedWidth
|
||||
{
|
||||
get => GetValue(ClosedWidthProperty);
|
||||
set => SetValue(ClosedWidthProperty, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static NavigationMenu()
|
||||
{
|
||||
SelectedItemProperty.Changed.AddClassHandler<NavigationMenu>((o, e) => o.OnSelectionItemChanged(e));
|
||||
IsClosedProperty.Changed.AddClassHandler<NavigationMenu>((o,e)=>o.OnIsClosedChanged(e));
|
||||
}
|
||||
|
||||
private void OnSelectionItemChanged(AvaloniaPropertyChangedEventArgs args)
|
||||
{
|
||||
var newItem = args.GetNewValue<object?>();
|
||||
if (newItem is not null)
|
||||
{
|
||||
UpdateSelectionFromSelectedItem(newItem);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIsClosedChanged(AvaloniaPropertyChangedEventArgs args)
|
||||
{
|
||||
bool newValue = args.GetNewValue<bool>();
|
||||
PseudoClasses.Set(PC_Closed, newValue);
|
||||
}
|
||||
|
||||
internal void UpdateSelection(NavigationMenuItem source)
|
||||
@@ -48,15 +124,7 @@ public class NavigationMenu: HeaderedSelectingItemsControl
|
||||
{
|
||||
foreach (var child in children)
|
||||
{
|
||||
NavigationMenuItem? item = null;
|
||||
if (child is NavigationMenuItem i)
|
||||
{
|
||||
item = i;
|
||||
}
|
||||
else if (child is ContentPresenter { Child: NavigationMenuItem i2 })
|
||||
{
|
||||
item = i2;
|
||||
}
|
||||
NavigationMenuItem? item = NavigationMenuItem.GetMenuItemFromControl(child);
|
||||
if (item != null)
|
||||
{
|
||||
if(Equals(item, source)) continue;
|
||||
@@ -65,4 +133,18 @@ public class NavigationMenu: HeaderedSelectingItemsControl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSelectionFromSelectedItem(object? o)
|
||||
{
|
||||
var children = this.ItemsPanelRoot?.Children;
|
||||
if (children is not null)
|
||||
{
|
||||
foreach (var child in children)
|
||||
{
|
||||
NavigationMenuItem? item = NavigationMenuItem.GetMenuItemFromControl(child);
|
||||
if(item is null) continue;
|
||||
item.UpdateSelectionFromSelectedItem(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.LogicalTree;
|
||||
@@ -12,16 +14,68 @@ using Avalonia.VisualTree;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
[PseudoClasses(PC_Closed, PC_Selected, PC_Empty)]
|
||||
[PseudoClasses(PC_Closed, PC_Selected, PC_Highlighted, PC_Collapsed)]
|
||||
public class NavigationMenuItem: HeaderedSelectingItemsControl
|
||||
{
|
||||
public const string PC_Closed = ":closed";
|
||||
public const string PC_Selected = ":selected";
|
||||
public const string PC_Empty = ":empty";
|
||||
public const string PC_Highlighted= ":highlighted";
|
||||
public const string PC_Collapsed = ":collapsed";
|
||||
|
||||
private NavigationMenu? _rootMenu;
|
||||
private IDisposable? _ownerSubscription;
|
||||
private IDisposable? _itemsBinding;
|
||||
private bool _isCollapsed;
|
||||
|
||||
public static readonly StyledProperty<bool> IsClosedProperty = AvaloniaProperty.Register<NavigationMenuItem, bool>(
|
||||
nameof(IsClosed));
|
||||
|
||||
public bool IsClosed
|
||||
{
|
||||
get => GetValue(IsClosedProperty);
|
||||
set => SetValue(IsClosedProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<object?> IconProperty = AvaloniaProperty.Register<NavigationMenuItem, object?>(
|
||||
nameof(Icon));
|
||||
|
||||
public object? Icon
|
||||
{
|
||||
get => GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IDataTemplate> IconTemplateProperty = AvaloniaProperty.Register<NavigationMenuItem, IDataTemplate>(
|
||||
nameof(IconTemplate));
|
||||
|
||||
public IDataTemplate IconTemplate
|
||||
{
|
||||
get => GetValue(IconTemplateProperty);
|
||||
set => SetValue(IconTemplateProperty, value);
|
||||
}
|
||||
|
||||
private int _level;
|
||||
|
||||
public static readonly DirectProperty<NavigationMenuItem, int> LevelProperty = AvaloniaProperty.RegisterDirect<NavigationMenuItem, int>(
|
||||
nameof(Level), o => o.Level);
|
||||
|
||||
public int Level
|
||||
{
|
||||
get => _level;
|
||||
private set => SetAndRaise(LevelProperty, ref _level, value);
|
||||
}
|
||||
|
||||
static NavigationMenuItem()
|
||||
{
|
||||
IsClosedProperty.Changed.AddClassHandler<NavigationMenuItem>((o, e) => o.OnIsClosedChanged(e));
|
||||
}
|
||||
|
||||
private void OnIsClosedChanged(AvaloniaPropertyChangedEventArgs args)
|
||||
{
|
||||
bool newValue = args.GetNewValue<bool>();
|
||||
PseudoClasses.Set(PC_Closed, newValue);
|
||||
}
|
||||
|
||||
|
||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
@@ -35,6 +89,11 @@ public class NavigationMenuItem: HeaderedSelectingItemsControl
|
||||
{
|
||||
SetCurrentValue(ItemContainerThemeProperty, _rootMenu.ItemContainerTheme);
|
||||
}
|
||||
|
||||
_rootMenu?.GetObservable(NavigationMenu.IsClosedProperty)
|
||||
.Subscribe(new AnonymousObserver<bool>(a => this.IsClosed = a));
|
||||
|
||||
Level = CalculateDistanceFromLogicalParent<NavigationMenu>(this) - 1;
|
||||
}
|
||||
|
||||
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
||||
@@ -47,31 +106,38 @@ public class NavigationMenuItem: HeaderedSelectingItemsControl
|
||||
if (_rootMenu is not null && parents.Contains(_rootMenu))
|
||||
{
|
||||
object? o = this.DataContext ?? this;
|
||||
_rootMenu.SelectedMenuItem = o;
|
||||
_rootMenu.SelectedItem = o;
|
||||
}
|
||||
SetSelection(this, true, true);
|
||||
}
|
||||
// Non-leaf node, act as a toggle button.
|
||||
else
|
||||
{
|
||||
_isCollapsed = !_isCollapsed;
|
||||
this.PseudoClasses.Set(PC_Collapsed, _isCollapsed);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
SetSelection(this, true, true);
|
||||
|
||||
}
|
||||
|
||||
internal void SetSelection(NavigationMenuItem? source, bool selected, bool propagateToParent = false)
|
||||
{
|
||||
this.PseudoClasses.Set(PC_Selected, selected);
|
||||
if (Equals(this, source) && this.ItemCount == 0)
|
||||
{
|
||||
this.PseudoClasses.Set(PC_Highlighted, selected);
|
||||
this.PseudoClasses.Set(PC_Selected, selected);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PseudoClasses.Set(PC_Selected, false);
|
||||
this.PseudoClasses.Set(PC_Highlighted, selected);
|
||||
}
|
||||
var children = this.ItemsPanelRoot?.Children;
|
||||
if (children is not null)
|
||||
{
|
||||
foreach (var child in children)
|
||||
{
|
||||
NavigationMenuItem? item = null;
|
||||
if (child is NavigationMenuItem i)
|
||||
{
|
||||
item = i;
|
||||
}
|
||||
else if (child is ContentPresenter { Child: NavigationMenuItem i2 })
|
||||
{
|
||||
item = i2;
|
||||
}
|
||||
NavigationMenuItem? item = GetMenuItemFromControl(child);
|
||||
if (item != null)
|
||||
{
|
||||
if(Equals(item, source)) continue;
|
||||
@@ -96,4 +162,54 @@ public class NavigationMenuItem: HeaderedSelectingItemsControl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdateSelectionFromSelectedItem(object? o)
|
||||
{
|
||||
if (o is null)
|
||||
{
|
||||
this.SetSelection(this, false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Equals(this, o) || Equals(this.DataContext, o))
|
||||
{
|
||||
this.SetSelection(this, true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
var children = this.ItemsPanelRoot?.Children;
|
||||
if (children is not null)
|
||||
{
|
||||
foreach (var child in children)
|
||||
{
|
||||
NavigationMenuItem? item = GetMenuItemFromControl(child);
|
||||
if (item != null)
|
||||
{
|
||||
item.UpdateSelectionFromSelectedItem(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int CalculateDistanceFromLogicalParent<T>(ILogical? logical, int @default = -1) where T : class
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
while (logical != null && !(logical is T))
|
||||
{
|
||||
++result;
|
||||
logical = logical.LogicalParent;
|
||||
}
|
||||
|
||||
return logical != null ? result : @default;
|
||||
}
|
||||
|
||||
public static NavigationMenuItem? GetMenuItemFromControl(Control? control)
|
||||
{
|
||||
if (control is null) return null;
|
||||
if (control is NavigationMenuItem item) return item;
|
||||
if (control is ContentPresenter { Child: NavigationMenuItem item2 }) return item2;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user