1. 程式人生 > >WPF製作的一個小功能,輸入智慧提示(IntelliSense)

WPF製作的一個小功能,輸入智慧提示(IntelliSense)

最近WPF專案中遇到一個需求,需要給一個RichTextBox新增智慧提示(IntelliSense)功能。

分析下具體的需求,在使用者鍵入"@"符號時,應該顯示一個彈出框,把所有使用者列出。使用者可以通過鍵盤、滑鼠等進行選擇。使用者列表可能資料比較多,那麼使用者還應該可以輸入字元進行篩選。用過各種IDE開發工具的童鞋應該對這樣的效果很瞭解了,具體效果如下

輸入@符號的效果:

篩選的效果:

再談談具體的開發思路.

1.如何製作可以實現列表選擇功能的彈出框

  方法很多,Popup+ListBox可以完美解決.此處我為了省程式碼,直接用的ListBox

2.如何在鍵入@符號時,將ListBox顯示在@符號之後

  在VisualStudio的智慧提示裡,當我們觸發了IntelliSense時,提示框會顯示,並且與下一字元的插入點對齊。TextPointer類提供了方法可以獲取到某個插入點的座標:

     RichTextBox textbox = this.RichTextBox;
     TextPointer start = textbox.Selection.Start;
     Rect rect = start.GetCharacterRect(LogicalDirection.Forward);
     Point point = rect.BottomLeft;


  我們可以註冊RichTextBox的鍵盤事件,判斷使用者是否鍵入@符號。@符號是由“Shift”+“2”組成,Keyboard.Modifiers可以獲取到組合鍵:

 if (Keyboard.Modifiers == ModifierKeys.Shift && e.Key == Key.D2)
 {
     //TODO: 使用者鍵入了@符號
 }

在TODO裡,將ListBox移動到得到Point位置即可。

3.如何實現選擇和篩選

  篩選功能很簡單,儲存一個區域性變數,在智慧提示框顯示後記錄用戶輸入,智慧提示框隱藏後清空,智慧提示框中的資料按照該變數進行過濾即可。

  當智慧提示框顯示的時候,使用者是可以鍵入“上”,“下”鍵進行移動選擇的。也許在敲了幾次方向鍵,使用者還想繼續輸入字元進行篩選。最開始,我是用的ListBox自動的選擇功能,當用戶敲入方向鍵,我就將鍵盤焦點(WPF中分鍵盤焦點和邏輯焦點,這個也是困擾我很久的問題)設定到ListBox上,那麼使用者就可以敲入“上”,“下”鍵進行移動選擇了。看起來很簡單,但是這樣是有問題的,因為使用者如果想繼續敲入字元篩選,我還必須將鍵盤焦點重新設定到RichTextBox上,否則使用者的敲擊是無效的。

  後來突然想通了,在使用者敲擊“上”,“下”鍵時,只需要呼叫ListBox的MoveCurrentToPrevious()和MoveCurrentToNext()即可,這樣給使用者的錯覺還是有了上下移動的效果。焦點不在ListBox上時,這樣的移動可能造成當前選中項超出了顯示範圍之外,那麼可以通過ListBox的ScrollIntoView()方法,將選中物件滾動到檢視中。

  下面是擷取的一段程式碼:

//如果按了向下鍵,則把選中項下移 
       if (e.Key == Key.Down) 
       { 
           if (UserList.CurrentPosition != UserList.Count - 1) 
           { 
               lbUser.Items.MoveCurrentToNext(); 
               lbUser.ScrollIntoView(lbUser.Items.CurrentItem); 
           } 
           e.Handled = true; 
       } 
       //如果按了向上鍵,則把選中項上移 
       if (e.Key == Key.Up) 
       { 
           if (UserList.CurrentPosition != 0) 
           { 
               lbUser.Items.MoveCurrentToPrevious(); 
               lbUser.ScrollIntoView(lbUser.Items.CurrentItem); 
           } 
           e.Handled = true; 
       } 

4.實現選中和取消
選中功能就更簡單了,分別加入對滑鼠雙擊,空格,回車,TAB等的判斷,將ListBox的當前選中項的文字插入到RichTextBox中即可。需要注意的是,此處要對單擊做判定,由於單擊ListBox會使鍵盤焦點設定到其之上,因此要強制將鍵盤焦點從ListBox移開。判斷ESC鍵,使ListBox隱藏即可實現取消功能。

5.如何實現擴充套件

  做一個功能最重要的就是考慮以後的重用,此處可以公開KeyBoard.Modifyers,KeyCode,IEnumable<T>為依賴屬性,前2個代表在敲入什麼組合鍵時會彈出智慧提示框,最後一個是彈出內容的資料來源。由於此處的篩選功能是在控制元件內部,那麼我們可以定義一個介面,包含一個Name屬性。 

 public interface IData
 {
     //用於篩選和插入的名稱
     string Name { get; set; }
 }


將上面的IEnumable<T>改為IEnumable<IData>。

  以後的呼叫方,只需要將這3箇中的一個或多個傳入,即可實現智慧提示功能。