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() {