WPF开发经验-实现Win10虚拟触摸键盘
一 引入
项目有个需求,需要实现纯触控操作进行键盘输入。项目部署在Win10系统上,考虑有两种方案来实现。
- 通过调用Win10自带的触摸键盘来实现;
- 通过WPF实现一个触摸键盘来实现;
二 调用Win10自带的触摸键盘
简单附上一个调用Win10系统的TabTip.exe的操作类。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class TabTipHelper { private const int WM_SYSCOMMAND = 274; private const uint SC_CLOSE = 61536; private const uint SC_RESTORE = 0xF120; private const uint SC_MAXIMIZE = 0xF030; private const uint SC_MINIMIZE = 0xF020; [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern bool PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern bool PostMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern int RegisterWindowMessage(string lpString); public static int ShowTaptip() { try { dynamic file = "C:\\Program Files\\Common Files\\microsoft shared\\ink\\TabTip.exe"; if (!System.IO.File.Exists(file)) return -1; Process.Start(file); return 1; } catch (Exception) { return 255; } } public static async Task ShowTaptipAsync() { await Task.Run(() => ShowTaptip()); } public static void CloseTaptip() { var touchhWnd = new IntPtr(0); touchhWnd = FindWindow("IPTip_Main_Window", null); if (touchhWnd == IntPtr.Zero) return; PostMessage(touchhWnd, WM_SYSCOMMAND, SC_CLOSE, 0); } }
三 通过WPF实现一个触摸键盘
下图为demo效果:
当TextBox获取焦点时,弹出键盘。当TextBox失去焦点时,隐藏键盘。
点击键盘的右上角的关闭键或Esc键隐藏键盘。
因项目不需要全键位,所有针对性地对键位进行了删减和排列。
3.1 SoftKeyboardControl控件
使用WPF的UserControl实现虚拟键盘,下附SoftKeyboardControl的后台代码。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// SoftKeyboardControl.xaml 的交互逻辑 /// </summary> public partial class SoftKeyboardControl : UserControl { /// <summary> /// Windows提供的一个模拟键盘API。 /// Keybd_event()函数能触发一个按键事件,生成一个 WM_KEYDOWN 或 WM_KEYUP 消息。 /// </summary> /// <param name="bVk" >按键的虚拟键值</param> /// <param name= "bScan" >扫描码,一般不用设置,用0代替就行</param> /// <param name= "dwFlags" >选项标志:0:表示按下,2:表示松开</param> /// <param name= "dwExtraInfo">一般设置为0</param> [DllImport("User32.dll")] public static extern void keybd_event(byte bVK, byte bScan, int dwFlags, int dwExtraInfo); public SoftKeyboardControl() { InitializeComponent(); CreateKeys(); KeyCommand = new RoutedCommand(); CommandBinding cmdBinding = new CommandBinding(KeyCommand, KeyCommand_Excuted, KeyCommand_CanExcute); CommandBindings.Add(cmdBinding); } #region 虚拟键值 /// <summary> /// 键和虚拟键值的字典 /// </summary> private Dictionary<string, byte> keys; /// <summary> /// 初始化虚拟键值的字典 /// </summary> private void CreateKeys() { keys = new Dictionary<string, byte>() { #region 数字键盘 { "0",0x60}, { "1",0x61}, { "2",0x62}, { "3",0x63}, { "4",0x64}, { "5",0x65}, { "6",0x66}, { "7",0x67}, { "8",0x68}, { "9",0x69}, { "-",0x6d}, { ".",0x6E}, #endregion #region Q字母行 { "q", 0x51}, { "w", 0x57}, { "e", 0x45}, { "r", 0x52}, { "t", 0x54}, { "y", 0x59}, { "u", 0x55}, { "i", 0x49}, { "o", 0x4f}, { "p", 0x50}, { "Q", 0x51}, { "W", 0x57}, { "E", 0x45}, { "R", 0x52}, { "T", 0x54}, { "Y", 0x59}, { "U", 0x55}, { "I", 0x49}, { "O", 0x4f}, { "P", 0x50}, #endregion #region A字母行 { "a", 0x41}, { "s", 0x53}, { "d", 0x44}, { "f", 0x46}, { "g", 0x47}, { "h", 0x48}, { "j", 0x4A}, { "k", 0x4B}, { "l", 0x4C}, { "A", 0x41}, { "S", 0x53}, { "D", 0x44}, { "F", 0x46}, { "G", 0x47}, { "H", 0x48}, { "J", 0x4A}, { "K", 0x4B}, { "L", 0x4C}, #endregion #region Z字母行 { "z", 0x5A}, { "x", 0x58}, { "c", 0x43}, { "v", 0x56}, { "b", 0x42}, { "n", 0x4E}, { "m", 0x4D}, { "Z", 0x5A}, { "X", 0x58}, { "C", 0x43}, { "V", 0x56}, { "B", 0x42}, { "N", 0x4E}, { "M", 0x4D}, #endregion #region other {"BackSpace",0x08 }, {"Tab",0x09 }, {"Enter",0x0d }, {"Shift",0x10 }, {"Ctrl",0x11 }, {"CapsLock",0x14 }, {"Space",0x20 }, #endregion }; } #endregion #region DependencyProperty public static readonly DependencyProperty CapsProperty = DependencyProperty.Register( "Caps", typeof(bool), typeof(SoftKeyboardControl), new PropertyMetadata(default(bool))); public bool Caps { get { return (bool)GetValue(CapsProperty); } set { SetValue(CapsProperty, value); } } public static readonly DependencyProperty CtrlProperty = DependencyProperty.Register( "Ctrl", typeof(bool), typeof(SoftKeyboardControl), new PropertyMetadata(default(bool))); public bool Ctrl { get { return (bool)GetValue(CtrlProperty); } set { SetValue(CtrlProperty, value); } } public static readonly DependencyProperty ShiftProperty = DependencyProperty.Register( "Shift", typeof(bool), typeof(SoftKeyboardControl), new PropertyMetadata(default(bool))); public bool Shift { get { return (bool)GetValue(ShiftProperty); } set { SetValue(ShiftProperty, value); } } #endregion #region Command public ICommand KeyCommand { get; set; } private void KeyCommand_CanExcute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; } private void KeyCommand_Excuted(object sender, ExecutedRoutedEventArgs e) { if (e.Parameter != null) { var code = e.Parameter.ToString(); if (keys.ContainsKey(code)) { byte b = keys[code]; try { keybd_event(b, 0, 0, 0); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } } public ICommand CloseCommand { get; set; } #endregion protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { base.OnPropertyChanged(e); if (e.Property == CapsProperty) { keybd_event(0x14, 0, 0, 0);//按下 keybd_event(0x14, 0, 2, 0); //抬起 } else if (e.Property == ShiftProperty) { keybd_event(0x10, 0, 0, 0); keybd_event(0x10, 0, 2, 0); } else if (e.Property == CtrlProperty) { keybd_event(0x11, 0, 0, 0); keybd_event(0x11, 0, 2, 0); } } } /// <summary> /// 大小写转换 /// </summary> public class UpperConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (parameter == null) { return ""; } if (value == null) { return parameter.ToString(); } if ((bool)value) { return parameter.ToString().ToUpper(); } else { return parameter.ToString().ToLower(); } } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
下附SoftKeyboardControl的前台代码。
注:其中按钮的样式是自己的控件库中实现的,未贴出。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<UserControl x:Class="UI.View.SoftKeyboardControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:UI.View" mc:Ignorable="d" Background="#E6E6E6"> <UserControl.Resources> <local:UpperConverter x:Key="UpperConverter"/> </UserControl.Resources> <StackPanel Margin="6 0 6 6"> <StackPanel Height="40" Orientation="Horizontal" > <!--关闭按钮--> </StackPanel> <StackPanel Orientation="Horizontal" Margin="0 6 0 0" > <StackPanel> <WrapPanel> <Button Content="Esc" Width="85" Height="Auto" Padding="0" Command="{Binding CloseCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" /> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=q}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=w}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=e}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=r}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=t}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=y}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=u}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=i}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=o}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=p}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> </WrapPanel> <WrapPanel> <ToggleButton Width="100" Content="Caps" IsChecked="{Binding Caps,Mode=TwoWay,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=a}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=s}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=d}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=f}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=g}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=h}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=j}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=k}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=l}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> </WrapPanel> <WrapPanel> <ToggleButton Width="115" Padding="-18 0 0 0 " Content="Shift" IsChecked="{Binding Shift,Mode=TwoWay,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=z}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=x}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=c}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=v}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=b}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=n}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}, Converter={StaticResource UpperConverter},ConverterParameter=m}" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Width="125" Content="Enter" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> </WrapPanel> <WrapPanel> <ToggleButton Width="115" Padding="-28 0 0 0 " Content="Ctrl" IsChecked="{Binding Ctrl,Mode=TwoWay,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}"/> <Button Content="Space" Width="185" Margin="50 0 0 0" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="BackSpace" Width="170" Margin="50 0 0 0" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> </WrapPanel> </StackPanel> <Grid Width="auto" Height="auto"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Button Content="7" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="8" Grid.Column="1" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="9" Grid.Column="2" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="4" Grid.Row="1" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="5" Grid.Row="1" Grid.Column="1" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="6" Grid.Row="1" Grid.Column="2" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="1" Grid.Row="2" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="2" Grid.Row="2" Grid.Column="1" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="3" Grid.Row="2" Grid.Column="2" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="-" Grid.Row="3" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="0" Grid.Row="3" Grid.Column="1" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="." Grid.Row="3" Grid.Column="2" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> <Button Content="Esc" Grid.Row="0" Grid.Column="3" Grid.RowSpan="2" Margin="0,0,0,5" Width="56" Height="Auto" Padding="0" Command="{Binding CloseCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" /> <Button Grid.Row="2" Grid.Column="3" Grid.RowSpan="2" Height="auto" Width="56" Margin="0 0 0 4" Padding="0" Content="Enter" Command="{Binding KeyCommand,RelativeSource={RelativeSource AncestorType={x:Type local:SoftKeyboardControl}}}" CommandParameter="{Binding Path=Content,RelativeSource={RelativeSource Self}}"/> </Grid> </StackPanel> </StackPanel> </UserControl>
3.2 Demo界面的代码
下附Demo界面后台代码。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/// <summary> /// TestWindow.xaml 的交互逻辑 /// </summary> public partial class TestWindow : Window { public TestWindow() { InitializeComponent(); softKeyboard.CloseCommand = new RoutedCommand(); CommandBinding cmdBinding = new CommandBinding(softKeyboard.CloseCommand, CloseCommand_Excuted, CloseCommand_CanExcute); CommandBindings.Add(cmdBinding); } private void CloseCommand_CanExcute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = popup.IsOpen; } private void CloseCommand_Excuted(object sender, ExecutedRoutedEventArgs e) { popup.IsOpen = false; textBox.Focus(); } private void TextBox_GotFocus(object sender, RoutedEventArgs e) { popup.IsOpen = true; } private void TextBox_LostFocus(object sender, RoutedEventArgs e) { popup.IsOpen = false; } }
下附Demo界面的前台代码。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<Window x:Class="UI.View.TestWindow" 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" xmlns:view="clr-namespace:UI.View" Title="TestWindow" Height="800" Width="1400"> <Grid x:Name="grid"> <TextBox Margin="415,233,447,0" FontSize="30" Height="62" VerticalContentAlignment="Center" VerticalAlignment="Top" GotFocus="TextBox_GotFocus" LostFocus="TextBox_LostFocus" /> <TextBox x:Name="textBox" Margin="470,343,503,364" /> <Popup x:Name="popup" StaysOpen="True" AllowsTransparency="True" PopupAnimation="Fade" PlacementTarget="{Binding ElementName = grid}" Placement="Bottom" HorizontalOffset="250" VerticalOffset="-280"> <view:SoftKeyboardControl x:Name="softKeyboard"/> </Popup> </Grid> </Window>
四 参考链接
虚拟键码 (Winuser.h) - Win32 apps | Microsoft Docs
__ 以 上 __