搜尋合約讓應用整合至系統層級的搜尋體驗:使用者在任意處呼叫搜尋 Charm,輸入關鍵字即可搜尋應用內容。Windows 8 提供豐富的建議機制:本地靜態建議、遠端動態建議(含圖示/描述)、本地檔案屬性索引建議,並支援輸入法編輯器 (IME) 協作。本文完整實作各類搜尋建議與搜尋啟動處理。
| 類別 | 角色 | 關鍵成員 |
|---|---|---|
| SearchPane | 搜尋面板存取點 | GetForCurrentView()、Show()、PlaceholderText、SearchHistoryEnabled/Context、ShowOnKeyboardInput、QueryChanged/QuerySubmitted/SuggestionsRequested/ResultSuggestionChosen/VisibilityChanged |
| SearchPaneSuggestionsRequest | 建議請求處理器 | SearchSuggestionCollection、AppendQuerySuggestion/AppendQuerySuggestions/AppendResultSuggestion/AppendSearchSeparator、GetDeferral() |
| SearchPaneQueryLinguisticDetails | IME 輸入法細節 | QueryTextAlternatives、QueryTextCompositionStart/Length |
| LocalContentSuggestionSettings | 本地檔案索引建議設定 | Enabled、Locations、AqsFilter、PropertiesToMatch |
在「宣告」頁籤新增「搜尋」宣告,系統自動將應用加入搜尋來源清單。
protected override void OnSearchActivated(SearchActivatedEventArgs args) {
if (args.PreviousExecutionState == ApplicationExecutionState.Running) return;
var rootFrame = new Frame();
rootFrame.Navigate(typeof(MainPage), args); // 攜帶查詢文字
Window.Current.Content = rootFrame;
Window.Current.Activate();
}
protected override void OnNavigatedTo(NavigationEventArgs e) {
_searchPane = SearchPane.GetForCurrentView();
_searchPane.QueryChanged += OnQueryChanged;
_searchPane.QuerySubmitted += OnQuerySubmitted;
_searchPane.PlaceholderText = "請輸入關鍵字";
_searchPane.SearchHistoryEnabled = true;
_searchPane.SearchHistoryContext = "user_search"; // 區分不同搜尋情境的歷史
_searchPane.ShowOnKeyboardInput = true; // 直接輸入即喚出搜尋面板
// 若由搜尋啟動,取得查詢文字
var args = e.Parameter as SearchActivatedEventArgs;
if (args != null) ShowSearchPane(args.QueryText);
}
private void ShowSearchPane(string query = "") {
_searchPane.Show(query);
}
適用於固定詞彙庫(城市、產品代碼、標籤等),無需網路請求:
private static readonly string[] _cityList = {
"beijing", "北京", "beiji", "北極",
"shanghai", "上海", "tianjin", "天津",
"chongqing", "重慶"
};
private void OnSuggestionsRequested(SearchPane sender, SearchPaneSuggestionsRequestedEventArgs args) {
if (string.IsNullOrEmpty(args.QueryText)) return;
// 1. 根據 IME 輸入法候選字串篩選
foreach (var alt in args.LinguisticDetails.QueryTextAlternatives) {
foreach (var city in _cityList) {
if (city.StartsWith(alt, StringComparison.CurrentCultureIgnoreCase)) {
args.Request.SearchSuggestionCollection.AppendQuerySuggestion(city);
if (args.Request.SearchSuggestionCollection.Size >= 5) return;
}
}
}
// 2. 根據直接輸入文字篩選
foreach (var city in _cityList) {
if (city.StartsWith(args.QueryText, StringComparison.CurrentCultureIgnoreCase)) {
args.Request.SearchSuggestionCollection.AppendQuerySuggestion(city);
if (args.Request.SearchSuggestionCollection.Size >= 5) return;
}
}
}
關鍵點: QueryTextAlternatives 包含 IME 當前所有候選文字(如拼音輸入中「beij」對應「北京」「北極」),針對每個候選詞篩選可大幅提升中文輸入體驗。
適用於即時搜尋建議(電商商品、地址自動完成),支援圖示、描述、分隔線:
private HttpClient _httpClient = new HttpClient();
private Task _currentRequest;
private async void OnSuggestionsRequested(SearchPane sender, SearchPaneSuggestionsRequestedEventArgs args) {
var deferral = args.Request.GetDeferral(); // 開始異步操作
try {
// 取消上一個未完成請求
if (_currentRequest != null) _currentRequest.AsAsyncOperation().Cancel();
// 發起新請求(範例:淘寶建議 API)
_currentRequest = _httpClient.GetStringAsync(
$"https://suggest.taobao.com/sug?extras=1&code=utf-8&q={args.QueryText}");
string response = await _currentRequest;
var json = JsonObject.Parse(response);
var array = json["result"].GetArray();
foreach (var item in array) {
string suggestion = item.GetArray()[0].GetString();
// AppendResultSuggestion:文字 + 描述 + 標籤 + 圖示 + 替代文字
args.Request.SearchSuggestionCollection.AppendResultSuggestion(
suggestion, "描述文字", suggestion,
RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/Logo.png")),
"替代文字"
);
args.Request.SearchSuggestionCollection.AppendSearchSeparator("分隔線");
if (args.Request.SearchSuggestionCollection.Size >= 5) break;
}
} finally {
deferral.Complete(); // 完成異步操作
}
}
private void OnResultSuggestionChosen(SearchPane sender, SearchPaneResultSuggestionChosenEventArgs args) {
// 使用者點選圖文建議項(非純文字查詢)
lblStatus.Text = $"選中建議: {args.Tag}";
}
private void OnQuerySubmitted(SearchPane sender, SearchPaneQuerySubmittedEventArgs args) {
// 使用者提交純文字查詢(Enter 或點選純文字建議)
lblStatus.Text = $"提交查詢: {args.QueryText}";
}
關鍵差異:
AppendQuerySuggestion:純文字建議,使用者點選觸發 QuerySubmittedAppendResultSuggestion:豐富建議(文字+描述+圖示),使用者點選觸發 ResultSuggestionChosen,攜帶 Tag 參數GetDeferral()/Complete():非同步建議獲取必須配對使用利用 Windows 索引器搜尋檔案中繼資料(標題、作者、標籤等),無需自行索引:
protected override void OnNavigatedTo(NavigationEventArgs e) {
var settings = new LocalContentSuggestionSettings {
Enabled = true,
Locations = { KnownFolders.MusicLibrary }, // 需 Manifest 勾選「音樂庫」能力
AqsFilter = "kind:music", // AQS 查詢語法,限定音樂類型
PropertiesToMatch = {
"System.Title", "System.Music.Artist", "System.Music.AlbumTitle"
}
};
SearchPane.GetForCurrentView().SetLocalContentSuggestionSettings(settings);
}
AQS (Advanced Query Syntax) 範例:
kind:music、kind:picture、kind:documenttype:.mp3、type:.jpgauthor:"張三"、title:"報告"kind:music author:"周杰倫"前置條件: Manifest 勾選對應 Library 能力(音樂庫、圖片庫、文件庫等),檔案需經系統索引器掃描。
使用者開啟搜尋 Charm
↓
SearchPane.Visible = true → VisibilityChanged 事件
↓
使用者輸入文字(鍵盤/IME)
↓
ShowOnKeyboardInput = true → 自動 Show()
↓
文字變化 → QueryChanged 事件(即時回饋)
↓
系統觸發 SuggestionsRequested 事件
↓
應用異步獲取建議 → AppendQuerySuggestion / AppendResultSuggestion
↓
建議顯示於搜尋面板下方(最多 5 項)
↓
使用者操作:
├─ 選擇純文字建議 → QuerySubmitted (QueryText)
├─ 選擇圖文建議 → ResultSuggestionChosen (Tag)
└─ 直接按 Enter → QuerySubmitted (QueryText)
↓
應用處理查詢 → 顯示搜尋結果頁面
↓
SearchPane.Visible = false → VisibilityChanged 事件
SearchHistoryContext,避免歷史混雜。QueryTextAlternatives,中文/日文/韓文輸入體驗才完整。Size >= 5 判斷提前退出。Cancel()),避免舊回應覆蓋新結果(競態條件)。GetDeferral() 必須在同步程式碼中呼叫,Complete() 在 finally 區塊確保釋放。ResultSuggestionChosen 中直接導航至詳情頁。QuerySubmitted 統一導航至搜尋結果頁,攜帶 QueryText 參數。| 維度 | 搜尋合約 | 應用內搜尋框 |
|---|---|---|
| 進入點 | 系統 Charm (Win+Q) | 應用 UI 內部 |
| 可見性 | 全系統應用可被搜尋 | 僅應用內部 |
| 建議來源 | 系統統一面板 | 自行實作下拉/彈出 | 適用場景 | 內容導向型應用(新聞、電商、文件) | 工具型、社交型、高度自訂搜尋邏輯 |
| 實作複雜度 | 中(需處理啟動、建議、生命週期) | 低(完全自主控制) |
完整實作搜尋合約,能讓你的應用內容無縫接入 Windows 8 系統級搜尋體驗,大幅提升內容可發現性與使用者進入效率。