業務系統中,很多錄入人員習慣於用Enter鍵來代替Tab鍵切換控制項焦點(雖然我個人並不覺得這樣錄入速度會變得有多高效,呵呵),有需求了,自然就得想辦法滿足。
思路:為了更靈活的控制項焦點順序,我決定用TabIndex來做文章,每個輸入控制項按下斷行符號時,找到下一個比當前控制項TabIndex更大且最接近的控制項,然後focus().
XAML介面部分:
<UserControl x:Class="tab_key_test.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <StackPanel x:Name="LayoutRoot" Background="White"> <TextBox Margin="5" TabIndex="0"></TextBox> <CheckBox Margin="5" TabIndex="1" Content="CheckBox Test"></CheckBox> <TextBox Margin="5" TabIndex="2"></TextBox> <ComboBox Margin="5" TabIndex="3"> <ComboBox.Items> <ComboBoxItem Content="ComboBox Test 11"></ComboBoxItem> <ComboBoxItem Content="ComboBox Test 22"></ComboBoxItem> </ComboBox.Items> </ComboBox> <TextBox Margin="5" TabIndex="4"></TextBox> <RadioButton Margin="5" Content="Radio Test" TabIndex="5"></RadioButton> <TextBox Margin="5" TabIndex="6"></TextBox> </StackPanel></UserControl>
CS後端代碼:
using System;using System.Collections.Generic;using System.Linq;using System.Net;using System.Windows;using System.Windows.Controls;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Animation;using System.Windows.Shapes;namespace tab_key_test{ public partial class MainPage : UserControl { List<Control> allInputControls = new List<Control>(); public MainPage() { InitializeComponent(); this.Loaded += MainPage_Loaded; } void MainPage_Loaded(object sender, RoutedEventArgs e) { //把介面上的TextBox,RadioButton,ComboBox,CheckBox都加入列表 //註:一般業務錄入介面上只有這4種類型的輸入控制項,如果還有其實類型,可自行擴充 allInputControls.AddRange(FindChildren<TextBox>(LayoutRoot).Cast<Control>()); allInputControls.AddRange(FindChildren<RadioButton>(LayoutRoot).Cast<Control>()); allInputControls.AddRange(FindChildren<ComboBox>(LayoutRoot).Cast<Control>()); allInputControls.AddRange(FindChildren<CheckBox>(LayoutRoot).Cast<Control>()); //按TabIndex排序 allInputControls = allInputControls.OrderBy(c => c.TabIndex).ToList(); foreach (Control c in allInputControls) { c.KeyDown += EnterKeyDownToTab; if (c is ComboBox) { //ComboBox要特殊處理 (c as ComboBox).DropDownClosed += DropDownClosedToNext; } } } void EnterKeyDownToTab(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) { GoToNextControl(sender); } } void GoToNextControl(object sender) { var self = sender as Control; if (self == null) { return; } var selfTabIndex = self.TabIndex; //找出下一個控制項 var nextControl = allInputControls.FirstOrDefault(c => c.TabIndex > selfTabIndex); if (nextControl != null) { nextControl.Focus(); } else { allInputControls[0].Focus();//最後一個控制項時,再跳到第一個(可選處理) } } /// <summary> /// 尋找所有子項目(遞迴) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="parent"></param> /// <returns></returns> public static IEnumerable<T> FindChildren<T>(DependencyObject parent) where T : class { int count = VisualTreeHelper.GetChildrenCount(parent); if (count > 0) { for (int i = 0; i < count; i++) { DependencyObject child = VisualTreeHelper.GetChild(parent, i); var t = child as T; if (t != null) yield return t; IEnumerable<T> children = FindChildren<T>(child); foreach (T item in children) yield return item; } } } private void DropDownClosedToNext(object sender, EventArgs e) { GoToNextControl(sender); } }}
這個思路還可以應用到html網頁上:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Enter Key Replace Tab</title><script type="text/javascript" src="http://lib.sinaapp.com/js/jquery/1.6/jquery.min.js"></script><style type="text/css">input,select,textarea{padding:0;margin:5px;width:150px;display:block;}</style><script type="text/javascript">$(document).ready(function(){var inputs = $("input,textarea,select").sort(function(a,b){return a.tabIndex>b.tabIndex?1:-1});inputs.each(function(){$(this).keypress(function(e){if (e.keyCode==13||e.which==13){//修正textarea的多餘斷行符號問題(可選)//if ($(this).get(0).tagName == "TEXTAREA"){//$(this).val($.trim($(this).val()));//};var selfTabIndex = parseInt($(this).attr("tabIndex"),10);var nextInput = null;//找出下一個元素for(var i=0; i<inputs.length; i++){if (inputs[i].tabIndex > selfTabIndex){nextInput = inputs[i];break;}}if (nextInput != null){nextInput.focus();}else{inputs[0].focus();}}}).focus(function(){$(this).select();})})})</script></head><body><input type="text" tabindex="0" value="000"/><input type="text" tabindex="1" value="111"/><textarea tabindex="2">222</textarea><input type="radio" tabindex="3" id="r3" style="width:20px;display:inline"/><label for="r3">333</label><input type="text" tabindex="4" value="444"/><input type="checkbox" tabindex="5" id="c5" style="width:20px;display:inline"/><label for="c5">555</label><input type="text" tabindex="6" value="666"/><select tabindex="7"><option>777</option><option>xxx</option></select><select size="2" tabindex="8"><option>888</option><option>yyy</option></select></body></html>