WPF 輸入系統建立在路由事件、命令與焦點管理之上,支援滑鼠、鍵盤、觸控筆等多樣輸入裝置。本章詳細說明路由事件機制、三大輸入裝置事件表、命令架構與 CommandBinding 實作。
傳統 CLR 事件無處理器時視為無效;WPF 路由事件會沿視覺樹向上(Bubbling)或向下(Tunneling)傳遞,直到根節點。
MouseLeftButtonDown)。Preview 前綴(PreviewMouseLeftButtonDown),先於 Bubbling 引發。MouseEnter)。<Button MouseLeftButtonDown="Handler" PreviewMouseLeftButtonDown="PreviewHandler">
<Grid ...><Canvas ...><Ellipse .../></Canvas></Grid>
</Button>

點擊 Ellipse 時輸出順序:
PreviewButtonDownButton
PreviewButtonDownGrid
PreviewButtonDownCanvas
PreviewButtonDownEllipse
ButtonDownEllipse
ButtonDownCanvas
ButtonDownGrid
ButtonDownButton
在處理器中設定 e.Handled = true 可停止後續傳遞;若在 Preview 階段設定,Bubbling 階段也不會引發。
sender 為註冊處理器的元素;真實來源在 e.OriginalSource。
路由事件以標準 CLR 事件包裝暴露,支援 C# += 語法在後台代碼註冊,分離設計師與開發者關注點。
UIElement 定義大量滑鼠路由事件(MouseDown、MouseMove、MouseWheel 等),均為 Tunnel/Bubble 配對。IsMouseOver、IsDirectMouseOver 屬性指示滑鼠是否在元素或其子樹上。
Click 非基本輸入事件:由 ButtonBase 定義,滑鼠/鍵盤均可觸發。透明 Fill 的 Shape 仍可命中測試;若不欲攔截輸入,請完全不設定 Fill(而非透明筆刷)。
焦點決定鍵盤輸入目標。Focusable 決定元素可否獲焦點(Control 預設 true)。鍵盤事件(KeyDown、KeyUp、TextInput)同為 Tunnel/Bubble 配對。TextInput 為裝置無關文字輸入,手寫輸入亦會引發。
完整事件集:StylusDown/Up、StylusMove、StylusInAirMove、StylusInRange/OutOfRange、StylusSystemGesture、TextInput,均為 Tunnel/Bubble。
RoutedCommand 代表可由多種方式(選單、工具列、快捷鍵、腳本)調用的邏輯動作。命令以 Tunnel/Bubble 路由傳遞 PreviewExecute/Execute 事件。
| 類別 | 涵蓋命令 |
|---|---|
| ApplicationCommands | 剪貼簿、復原/重做、文件操作(開啟、列印) |
| ComponentCommands | 捲動、移動至末尾、文字選取 |
| EditCommands | 粗體、斜體、對齊 |
| MediaCommands | 播放/暫停、音量、軌道選擇 |
將命令對應至特定元素的處理器,解決單例命令全域觸發問題:
public Window1() {
InitializeComponent();
var binding = new CommandBinding(ApplicationCommands.New);
binding.Executed += NewCommandHandler;
CommandBindings.Add(binding);
}
void NewCommandHandler(object sender, ExecutedRoutedEventArgs e) {
if (unsavedChanges) { /* 詢問儲存 */ }
inputBox.Clear();
}
public static RoutedCommand FooCommand;
static Window1() {
var gestures = new InputGestureCollection();
gestures.Add(new KeyGesture(Key.F, ModifierKeys.Control | ModifierKeys.Shift));
FooCommand = new RoutedCommand("Foo", typeof(Window1), gestures);
}
XAML 綁定:<Button Command="ApplicationCommands.New" /> 或自訂 <Button Command="local:MyCommands.Foo" />(需 XML Mapping)。
var binding = new CommandBinding(ApplicationCommands.Redo);
binding.CanExecute += (s, e) => e.CanExecute = CanRedo();
CommandBindings.Add(binding);
已知問題:當前版本不會自動將選單/工具列項目灰化,僅阻止執行。
路由事件解決複合控制項輸入分發難題;命令系統統一多入口動作調用;兩者結合構建 WPF 豐富互動基礎。