diff --git a/Ink Canvas/Windows/SettingsViews/Pages/SearchPage.xaml b/Ink Canvas/Windows/SettingsViews/Pages/SearchPage.xaml
new file mode 100644
index 00000000..f2329216
--- /dev/null
+++ b/Ink Canvas/Windows/SettingsViews/Pages/SearchPage.xaml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ink Canvas/Windows/SettingsViews/Pages/SearchPage.xaml.cs b/Ink Canvas/Windows/SettingsViews/Pages/SearchPage.xaml.cs
new file mode 100644
index 00000000..eb23af42
--- /dev/null
+++ b/Ink Canvas/Windows/SettingsViews/Pages/SearchPage.xaml.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+using System.Windows.Input;
+using iNKORE.UI.WPF.Modern.Controls;
+
+namespace Ink_Canvas.Windows.SettingsViews.Pages
+{
+ public partial class SearchPage
+ {
+ ///
+ /// 选中搜索结果时触发,参数为 PageTag;"__back__" 表示返回
+ ///
+ public static event EventHandler ResultSelected;
+
+ // 由 SettingsWindow 设置的静态搜索数据
+ internal static List<(string Text, string PageTag)> SearchData { get; set; }
+
+ public SearchPage()
+ {
+ InitializeComponent();
+ Loaded += (s, e) =>
+ {
+ Dispatcher.BeginInvoke(new Action(() => SearchBox.Focus()),
+ System.Windows.Threading.DispatcherPriority.Input);
+ };
+ }
+
+ private void SearchBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
+ {
+ if (SearchData == null) return;
+
+ string raw = (args.ChosenSuggestion as string) ?? args.QueryText;
+ if (string.IsNullOrWhiteSpace(raw)) return;
+
+ string query = raw.Trim();
+ var match = SearchData.Where(e => e.Text.Equals(query, StringComparison.OrdinalIgnoreCase))
+ .Concat(SearchData.Where(e => e.Text.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0))
+ .FirstOrDefault();
+
+ if (match.Text != null)
+ {
+ ResultSelected?.Invoke(this, match.PageTag);
+ }
+ }
+
+ private void SearchBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
+ {
+ if (args.Reason != AutoSuggestionBoxTextChangeReason.UserInput) return;
+ if (SearchData == null) return;
+
+ string query = sender.Text?.Trim() ?? string.Empty;
+ if (string.IsNullOrEmpty(query))
+ {
+ sender.ItemsSource = null;
+ HintText.Visibility = Visibility.Visible;
+ return;
+ }
+
+ HintText.Visibility = Visibility.Collapsed;
+
+ var suggestions = SearchData
+ .Where(e => e.Text.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0)
+ .Select(e => e.Text)
+ .Distinct()
+ .Take(50)
+ .ToList();
+
+ sender.ItemsSource = suggestions;
+ sender.IsSuggestionListOpen = suggestions.Count > 0;
+ }
+
+ private void SearchBox_GotFocus(object sender, RoutedEventArgs e)
+ {
+ if (!string.IsNullOrEmpty(SearchBox.Text))
+ {
+ SearchBox.IsSuggestionListOpen = true;
+ }
+ }
+
+ private void SearchBox_KeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.Key == Key.Escape)
+ {
+ ResultSelected?.Invoke(this, "__back__");
+ }
+ }
+ }
+}
diff --git a/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml b/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml
index 01566dac..b74ce5a1 100644
--- a/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml
+++ b/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml
@@ -107,7 +107,8 @@ Title="{x:Static props:NavStrings.Nav_SettingsWindow_Title}"
x:FieldModifier="public"
PlaceholderText="{x:Static props:NavStrings.Nav_SearchSettings}"
QuerySubmitted="OnControlsSearchBoxQuerySubmitted"
- TextChanged="OnControlsSearchBoxTextChanged">
+ TextChanged="OnControlsSearchBoxTextChanged"
+ GotFocus="OnControlsSearchBoxGotFocus">
diff --git a/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs b/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs
index fbe8590c..c3dc3909 100644
--- a/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs
+++ b/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs
@@ -51,7 +51,8 @@ public partial class SettingsWindow : Window
{ "AboutPage", typeof(AboutPage) },
{ "Settings", typeof(SettingsPage) },
{ "PluginPage", typeof(PluginPage) },
- { "PluginSettingsPage", typeof(PluginSettingsPage) }
+ { "PluginSettingsPage", typeof(PluginSettingsPage) },
+ { "SearchPage", typeof(SearchPage) }
};
private Dictionary _pageTypes;
private readonly Dictionary _pages = new Dictionary();
@@ -112,7 +113,8 @@ public SettingsWindow()
{ "AboutPage", typeof(AboutPage) },
{ "Settings", typeof(SettingsPage) },
{ "PluginPage", typeof(PluginPage) },
- { "PluginSettingsPage", typeof(PluginSettingsPage) }
+ { "PluginSettingsPage", typeof(PluginSettingsPage) },
+ { "SearchPage", typeof(SearchPage) }
};
// 默认选中首页
@@ -150,10 +152,12 @@ public SettingsWindow()
};
AnnouncementService.UnreadCountChanged += UpdateAnnouncementUnreadBadge;
+ SearchPage.ResultSelected += OnSearchPageResultSelected;
this.Closed += (sender, e) =>
{
AnnouncementService.UnreadCountChanged -= UpdateAnnouncementUnreadBadge;
+ SearchPage.ResultSelected -= OnSearchPageResultSelected;
UnregisterDpiChangedListener();
_pages.Clear();
_pageTypes.Clear();
@@ -737,6 +741,31 @@ private void OnControlsSearchBoxTextChanged(AutoSuggestBox sender, AutoSuggestBo
sender.ItemsSource = suggestions;
}
+ private void OnControlsSearchBoxGotFocus(object sender, RoutedEventArgs e)
+ {
+ // 构建搜索索引并传给 SearchPage
+ EnsureSearchIndexBuilt();
+ SearchPage.SearchData = _searchIndex
+ .Select(se => (se.Text, se.PageTag))
+ .ToList();
+ NavigateToPage("SearchPage");
+ NavigationViewControl.Header = NavStrings.Nav_SearchSettings;
+ // 取消侧边栏选中状态
+ NavigationViewControl.SelectedItem = null;
+ }
+
+ private void OnSearchPageResultSelected(object sender, string pageTag)
+ {
+ if (pageTag == "__back__")
+ {
+ // 返回上一页
+ if (rootFrame.CanGoBack) rootFrame.GoBack();
+ return;
+ }
+
+ NavigateToSearchEntry(_searchIndex?.FirstOrDefault(e => e.PageTag == pageTag));
+ }
+
// 统一获取所有导航项(主菜单+子菜单+底部菜单)
private List GetAllNavigationItems()
{