feat: add function to set selected item from outside and sync to UI.

This commit is contained in:
rabbitism
2024-02-14 11:40:19 +08:00
parent f67a5a313c
commit 122f89fc57
4 changed files with 133 additions and 12 deletions

View File

@@ -26,10 +26,10 @@
Grid.ColumnSpan="2"> Grid.ColumnSpan="2">
Collapse Collapse
</ToggleButton> </ToggleButton>
<TextBlock <StackPanel Grid.Row="1" Grid.Column="0">
Grid.Row="1" <TextBlock Text="{Binding SelectedMenuItem.Header}" />
Grid.Column="0" <Button Command="{Binding RandomCommand}">Random a selection</Button>
Text="{ReflectionBinding #menu.SelectedItem.Header}" /> </StackPanel>
<Border <Border
Grid.Row="2" Grid.Row="2"
Grid.Column="0" Grid.Column="0"
@@ -42,6 +42,7 @@
IconBinding="{Binding IconIndex}" IconBinding="{Binding IconIndex}"
IsHorizontalCollapsed="{Binding #collapse.IsChecked, Mode=OneWay}" IsHorizontalCollapsed="{Binding #collapse.IsChecked, Mode=OneWay}"
ItemsSource="{Binding MenuItems}" ItemsSource="{Binding MenuItems}"
SelectedItem="{Binding SelectedMenuItem}"
SubMenuBinding="{Binding Children}"> SubMenuBinding="{Binding Children}">
<u:NavMenu.Styles> <u:NavMenu.Styles>
<Style x:DataType="vm:MenuItem" Selector="u|NavMenuItem"> <Style x:DataType="vm:MenuItem" Selector="u|NavMenuItem">
@@ -62,20 +63,20 @@
</DataTemplate> </DataTemplate>
</u:NavMenu.IconTemplate> </u:NavMenu.IconTemplate>
<u:NavMenu.Header> <u:NavMenu.Header>
<Grid ColumnDefinitions="Auto, Auto" HorizontalAlignment="Center"> <Grid HorizontalAlignment="Center" ColumnDefinitions="Auto, Auto">
<Image <Image
u:NavMenu.CanToggle="True"
Width="48" Width="48"
Height="48" Height="48"
Margin="4 12" Margin="4,12"
u:NavMenu.CanToggle="True"
RenderOptions.BitmapInterpolationMode="HighQuality" RenderOptions.BitmapInterpolationMode="HighQuality"
Source="../Assets/Ursa.ico" /> Source="../Assets/Ursa.ico" />
<TextBlock <TextBlock
Grid.Column="1" Grid.Column="1"
Classes="H5"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="Ursa Avalonia" Classes="H5"
IsVisible="{Binding !#menu.IsHorizontalCollapsed}" IsVisible="{Binding !#menu.IsHorizontalCollapsed}"
Text="Ursa Avalonia"
Theme="{DynamicResource TitleTextBlock}" /> Theme="{DynamicResource TitleTextBlock}" />
</Grid> </Grid>
</u:NavMenu.Header> </u:NavMenu.Header>

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;
@@ -9,6 +10,13 @@ namespace Ursa.Demo.ViewModels;
public class NavMenuDemoViewModel: ObservableObject public class NavMenuDemoViewModel: ObservableObject
{ {
private MenuItem? _selectedMenuItem;
public MenuItem? SelectedMenuItem
{
get=>_selectedMenuItem;
set => SetProperty(ref _selectedMenuItem, value);
}
public ObservableCollection<MenuItem> MenuItems { get; set; } = new ObservableCollection<MenuItem> public ObservableCollection<MenuItem> MenuItems { get; set; } = new ObservableCollection<MenuItem>
{ {
new MenuItem { Header = "Introduction" , Children = new MenuItem { Header = "Introduction" , Children =
@@ -54,6 +62,30 @@ public class NavMenuDemoViewModel: ObservableObject
new MenuItem { Header = "TwoTonePathIcon" }, new MenuItem { Header = "TwoTonePathIcon" },
new MenuItem { Header = "ThemeToggler" } new MenuItem { Header = "ThemeToggler" }
}; };
public ICommand RandomCommand { get; set; }
public NavMenuDemoViewModel()
{
RandomCommand = new RelayCommand(OnRandom);
}
private void OnRandom()
{
var items = GetLeaves();
var index = new Random().Next(items.Count);
SelectedMenuItem = items[index];
}
private List<MenuItem> GetLeaves()
{
List<MenuItem> items = new();
foreach (var item in MenuItems)
{
items.AddRange(item.GetLeaves());
}
return items;
}
} }
public class MenuItem public class MenuItem
@@ -77,4 +109,22 @@ public class MenuItem
} }
public ObservableCollection<MenuItem> Children { get; set; } = new ObservableCollection<MenuItem>(); public ObservableCollection<MenuItem> Children { get; set; } = new ObservableCollection<MenuItem>();
public IEnumerable<MenuItem> GetLeaves()
{
if (this.Children.Count == 0)
{
yield return this;
yield break;
}
foreach (var child in Children)
{
var items = child.GetLeaves();
foreach (var item in items)
{
yield return item;
}
}
}
} }

View File

@@ -1,4 +1,5 @@
using System.Diagnostics; using System.Diagnostics;
using System.Reflection;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
@@ -164,7 +165,25 @@ public class NavMenu: ItemsControl
private void OnSelectedItemChange(AvaloniaPropertyChangedEventArgs<object?> args) private void OnSelectedItemChange(AvaloniaPropertyChangedEventArgs<object?> args)
{ {
Debug.WriteLine(args.NewValue.Value); if (_updateFromUI) return;
var newValue = args.NewValue.Value;
if (newValue is null)
{
ClearAll();
return;
}
var leaves = GetLeafMenus();
bool found = false;
foreach (var leaf in leaves)
{
if (leaf == newValue || leaf.DataContext == newValue)
{
leaf.SelectItem(leaf);
found = true;
}
}
if (found) return;
ClearAll();
} }
protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey) protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey)
@@ -177,8 +196,11 @@ public class NavMenu: ItemsControl
return new NavMenuItem(); return new NavMenuItem();
} }
private bool _updateFromUI;
internal void SelectItem(NavMenuItem item, NavMenuItem parent) internal void SelectItem(NavMenuItem item, NavMenuItem parent)
{ {
_updateFromUI = true;
// if (item.IsSelected) return; // if (item.IsSelected) return;
foreach (var child in LogicalChildren) foreach (var child in LogicalChildren)
{ {
@@ -199,6 +221,34 @@ public class NavMenu: ItemsControl
{ {
SelectedItem = item; SelectedItem = item;
} }
item.IsSelected = true; item.BringIntoView();
// item.IsSelected = true;
_updateFromUI = false;
}
private IEnumerable<NavMenuItem> GetLeafMenus()
{
foreach (var child in LogicalChildren)
{
if (child is NavMenuItem item)
{
var leafs = item.GetLeafMenus();
foreach (var leaf in leafs)
{
yield return leaf;
}
}
}
}
private void ClearAll()
{
foreach (var child in LogicalChildren)
{
if (child is NavMenuItem item)
{
item.ClearSelection();
}
}
} }
} }

View File

@@ -265,7 +265,7 @@ public class NavMenuItem: HeaderedSelectingItemsControl
e.Handled = true; e.Handled = true;
} }
protected void SelectItem(NavMenuItem item) internal void SelectItem(NavMenuItem item)
{ {
if (item == this) if (item == this)
{ {
@@ -329,4 +329,24 @@ public class NavMenuItem: HeaderedSelectingItemsControl
return logical != null ? result : @default; return logical != null ? result : @default;
} }
internal IEnumerable<NavMenuItem> GetLeafMenus()
{
if (this.ItemCount == 0)
{
yield return this;
yield break;
}
foreach (var child in LogicalChildren)
{
if (child is NavMenuItem item)
{
var items = item.GetLeafMenus();
foreach (var i in items)
{
yield return i;
}
}
}
}
} }