diff --git a/Ink Canvas/Windows/SettingsViews/Pages/StoragePage.xaml b/Ink Canvas/Windows/SettingsViews/Pages/StoragePage.xaml index 88fa0d3a..3667ba3c 100644 --- a/Ink Canvas/Windows/SettingsViews/Pages/StoragePage.xaml +++ b/Ink Canvas/Windows/SettingsViews/Pages/StoragePage.xaml @@ -223,14 +223,14 @@ - - + + - + - + diff --git a/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs b/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs index df239f94..93e9b628 100644 --- a/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs +++ b/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs @@ -442,38 +442,180 @@ namespace Ink_Canvas.Windows.SettingsViews #endregion #region 搜索框逻辑优化 + + private sealed class SearchEntry + { + public string Text; + public string PageTag; + public WeakReference Target; + } + + private List _searchIndex; + private bool _indexBuilt; + + private void EnsureSearchIndexBuilt() + { + if (_indexBuilt && _searchIndex != null) return; + _searchIndex = new List(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(target) + }); + } + } + } + + private static IEnumerable EnumerateLogicalDescendants(DependencyObject root) + { + if (root == null) yield break; + var stack = new Stack(); + 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(); + 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; }