improve:设置索引

This commit is contained in:
2026-05-01 21:38:53 +08:00
parent a8c9734a5a
commit 31aee3bd9a
2 changed files with 165 additions and 23 deletions
@@ -223,14 +223,14 @@
</ui:SettingsCard>
<!-- 其他 -->
<ui:SettingsExpander x:Name="OtherExpander"
Header="{i18n:I18n Key=Storage_Other_Header}"
Description="{i18n:I18n Key=Storage_Other_Desc}">
<ui:SettingsExpander.HeaderIcon>
<ui:SettingsCard x:Name="OtherExpander"
Header="{i18n:I18n Key=Storage_Other_Header}"
Description="{i18n:I18n Key=Storage_Other_Desc}">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.More}"/>
</ui:SettingsExpander.HeaderIcon>
</ui:SettingsCard.HeaderIcon>
<TextBlock x:Name="OtherSizeText" Text="—" FontWeight="SemiBold" VerticalAlignment="Center"/>
</ui:SettingsExpander>
</ui:SettingsCard>
<Rectangle Height="48" />
@@ -442,38 +442,180 @@ namespace Ink_Canvas.Windows.SettingsViews
#endregion
#region
private sealed class SearchEntry
{
public string Text;
public string PageTag;
public WeakReference<FrameworkElement> Target;
}
private List<SearchEntry> _searchIndex;
private bool _indexBuilt;
private void EnsureSearchIndexBuilt()
{
if (_indexBuilt && _searchIndex != null) return;
_searchIndex = new List<SearchEntry>(256);
foreach (var item in GetAllNavigationItems())
{
var text = item.Content?.ToString();
var tag = item.Tag as string;
if (!string.IsNullOrWhiteSpace(text) && !string.IsNullOrEmpty(tag))
{
_searchIndex.Add(new SearchEntry { Text = text.Trim(), PageTag = tag });
}
}
foreach (var kv in _pageTypes.ToList())
{
var tag = kv.Key;
if (tag == "Settings") continue;
if (kv.Value == typeof(PluginSettingsPage)) continue;
try
{
if (!_pages.TryGetValue(tag, out var page))
{
page = Activator.CreateInstance(kv.Value);
_pages[tag] = page;
}
if (page is FrameworkElement feRoot)
{
if (!feRoot.IsLoaded)
{
try { feRoot.ApplyTemplate(); } catch { }
}
CollectEntriesFromPage(feRoot, tag);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"为页面 {tag} 建索引失败: {ex.Message}");
}
}
foreach (var kv in _pluginPages)
{
var pageTag = kv.Key;
var info = kv.Value;
var name = info?.Name;
if (!string.IsNullOrWhiteSpace(name))
{
_searchIndex.Add(new SearchEntry { Text = $"{name} 设置", PageTag = pageTag });
}
}
_indexBuilt = true;
}
private void CollectEntriesFromPage(DependencyObject root, string pageTag)
{
foreach (var node in EnumerateLogicalDescendants(root))
{
string header = null;
FrameworkElement target = node as FrameworkElement;
if (node is Ink_Canvas.Controls.LabeledSettingsCard lsc)
{
header = lsc.Header;
}
else if (node is iNKORE.UI.WPF.Modern.Controls.SettingsCard sc)
{
header = sc.Header?.ToString();
}
else if (node is iNKORE.UI.WPF.Modern.Controls.SettingsExpander se)
{
header = se.Header?.ToString();
}
if (!string.IsNullOrWhiteSpace(header) && target != null)
{
_searchIndex.Add(new SearchEntry
{
Text = header.Trim(),
PageTag = pageTag,
Target = new WeakReference<FrameworkElement>(target)
});
}
}
}
private static IEnumerable<DependencyObject> EnumerateLogicalDescendants(DependencyObject root)
{
if (root == null) yield break;
var stack = new Stack<DependencyObject>();
stack.Push(root);
while (stack.Count > 0)
{
var node = stack.Pop();
yield return node;
foreach (var child in LogicalTreeHelper.GetChildren(node))
{
if (child is DependencyObject d) stack.Push(d);
}
}
}
private void NavigateToSearchEntry(SearchEntry entry)
{
if (entry == null) return;
NavigateToPage(entry.PageTag);
var navItem = FindNavigationViewItemByTag(entry.PageTag);
if (navItem != null && NavigationViewControl.SelectedItem != navItem)
{
NavigationViewControl.SelectedItem = navItem;
NavigationViewControl.Header = navItem.Content;
}
if (entry.Target != null && entry.Target.TryGetTarget(out var fe))
{
Dispatcher.BeginInvoke(new Action(() =>
{
try { fe.BringIntoView(); } catch { }
}), System.Windows.Threading.DispatcherPriority.Background);
}
}
private void OnControlsSearchBoxQuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
if (string.IsNullOrWhiteSpace(args.QueryText)) return;
EnsureSearchIndexBuilt();
string query = args.QueryText.Trim().ToLower();
var allNavItems = GetAllNavigationItems();
string raw = (args.ChosenSuggestion as string) ?? args.QueryText;
if (string.IsNullOrWhiteSpace(raw)) return;
var targetItem = allNavItems.FirstOrDefault(item =>
item.Content?.ToString().ToLower().Contains(query) == true);
string query = raw.Trim();
string queryLower = query.ToLower();
if (targetItem != null)
{
NavigationViewControl.SelectedItem = targetItem;
}
var entry = _searchIndex.FirstOrDefault(e => e.Text.Equals(query, StringComparison.OrdinalIgnoreCase))
?? _searchIndex.FirstOrDefault(e => e.Text.ToLower().Contains(queryLower));
NavigateToSearchEntry(entry);
}
private void OnControlsSearchBoxTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
if (args.Reason != AutoSuggestionBoxTextChangeReason.UserInput) return;
string query = sender.Text.Trim().ToLower();
var suggestions = new List<string>();
EnsureSearchIndexBuilt();
if (!string.IsNullOrEmpty(query))
string query = sender.Text?.Trim() ?? string.Empty;
if (string.IsNullOrEmpty(query))
{
var allNavItems = GetAllNavigationItems();
suggestions = allNavItems
.Where(item => item.Content?.ToString().ToLower().Contains(query) == true)
.Select(item => item.Content.ToString())
.ToList();
sender.ItemsSource = null;
return;
}
string queryLower = query.ToLower();
var suggestions = _searchIndex
.Where(e => e.Text.ToLower().Contains(queryLower))
.Select(e => e.Text)
.Distinct()
.Take(50)
.ToList();
sender.ItemsSource = suggestions;
}