一 引入 项目有个新需求,当点击或触碰TextBox时,基于TextBox的相对位置,弹出一个自定义的Keyboard:
二 KeyboardControl先实现一个自定义的KeyboardControl,它继承自Window。 Xaml代码如下: - <Window x:Class="WpfApp1.KeyboardControl"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:local="clr-namespace:WpfApp1" AllowsTransparency="True" WindowStyle="None"
- ResizeMode="NoResize" Background="Transparent" Height="290" Width="668">
- <FrameworkElement.Resources>
- <ResourceDictionary>
- <Style TargetType="{x:Type Button}" x:Key="btnNum">
- <Setter Property="Width" Value="50"/>
- <Setter Property="Height" Value="50"/>
- <Setter Property="Margin" Value="0 0 5 5"/>
- <Setter Property="HorizontalContentAlignment" Value="Center" />
- <Setter Property="VerticalContentAlignment" Value="Center" />
- <Setter Property="Cursor" Value="Hand"/>
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="{x:Type Button}">
- <Border Name="border" BorderBrush="#FF474747" BorderThickness="1" CornerRadius="6">
- <Border.Background>
- <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
- <GradientStop Color="#FFCCCCCC" />
- <GradientStop Color="WhiteSmoke" Offset="0.5" />
- <GradientStop Color="#FFCCCCCC" Offset="1" />
- </LinearGradientBrush>
- </Border.Background>
- <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"
- TextElement.Foreground="#333333" TextElement.FontSize="18" />
- </Border>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
- <Style TargetType="{x:Type Button}" x:Key="btnFunc">
- <Setter Property="HorizontalContentAlignment" Value="Center" />
- <Setter Property="VerticalContentAlignment" Value="Center" />
- <Setter Property="Width" Value="50"/>
- <Setter Property="Height" Value="50"/>
- <Setter Property="Margin" Value="0 0 5 5"/>
- <Setter Property="Foreground" Value="#333333"/>
- <Setter Property="Cursor" Value="Hand"/>
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="{x:Type Button}">
- <Border
- Name="border"
- BorderBrush="#FF565656"
- BorderThickness="1"
- CornerRadius="6" Background="Orange">
- <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"
- TextElement.Foreground="White" TextElement.FontSize="18" />
- </Border>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
- <local:CapsConverter x:Key="CapsConverter"/>
- </ResourceDictionary>
- </FrameworkElement.Resources>
- <Border Background="Gray" CornerRadius="6" BorderThickness="1" BorderBrush="#333333">
- <StackPanel Margin="5 10 5 5" >
- <Grid>
- <TextBox Name="tbValue" FontSize="28" Height="40"
- Background="Transparent" BorderBrush="Silver" BorderThickness="1"
- Foreground="White" HorizontalContentAlignment="Right"
- SelectionChanged="tbValue_TextChanged"
- TextChanged="tbValue_TextChanged" />
- </Grid>
- <WrapPanel Orientation="Vertical" >
- <WrapPanel Margin="0 10 0 0">
- <Button Content="1" Click="Button_Click" Style="{StaticResource btnNum}" />
- <Button Content="2" Click="Button_Click" Style="{StaticResource btnNum}" />
- <Button Content="3" Click="Button_Click" Style="{StaticResource btnNum}" />
- <Button Content="4" Click="Button_Click" Style="{StaticResource btnNum}" />
- <Button Content="5" Click="Button_Click" Style="{StaticResource btnNum}" />
- <Button Content="6" Click="Button_Click" Style="{StaticResource btnNum}" />
- <Button Content="7" Click="Button_Click" Style="{StaticResource btnNum}" />
- <Button Content="8" Click="Button_Click" Style="{StaticResource btnNum}" />
- <Button Content="9" Click="Button_Click" Style="{StaticResource btnNum}" />
- <Button Content="0" Click="Button_Click" Style="{StaticResource btnNum}" />
- <Button Content="-" Click="Button_Click" Style="{StaticResource btnNum}" />
- <Button Content="Del" Click="DELButton_Click" Style="{StaticResource btnFunc}" Margin="0 0 0 5"/>
- </WrapPanel>
- <WrapPanel Margin="25 0 0 0">
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=q}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=w}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=e}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=r}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=t}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=y}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=u}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=i}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=o}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=p}"
- Click="Button_Click"/>
- <Button Content="Clear" Click="ClearButton_Click" Style="{StaticResource btnFunc}" />
- </WrapPanel>
- <WrapPanel Margin="45 0 0 0">
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=a}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=s}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=d}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=f}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=g}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=h}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=j}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=k}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=l}"
- Click="Button_Click"/>
- <Button Content="." Click="Button_Click" Style="{StaticResource btnNum}" />
- </WrapPanel>
- <WrapPanel Margin="70 0 0 0">
- <Button Content="A/a" Click="CapsButton_Click" Style="{StaticResource btnFunc}" />
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=z}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=x}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=c}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=v}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=b}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=n}"
- Click="Button_Click"/>
- <Button Style="{StaticResource btnNum}" Content="{Binding Path=Caps,RelativeSource={RelativeSource AncestorType={x:Type local:KeyboardControl}},Converter={StaticResource CapsConverter},ConverterParameter=m}"
- Click="Button_Click"/>
- <Button Content="Cancel" Click="CancelButton_Click" IsCancel="True" Style="{StaticResource btnFunc}" Width="70" />
- <Button Content="OK" Click="OKButton_Click" IsDefault="True" Style="{StaticResource btnFunc}" Width="70" Margin="0 0 0 5"/>
- </WrapPanel>
- </WrapPanel>
- </StackPanel>
- </Border>
- </Window>
复制代码后台代码如下:
- public partial class KeyboardControl : Window
- {
- private int TextIndex { get; set; }
- public string TextStr { get; private set; }//通过该属性,访问Keyboard的文本
- public KeyboardControl(string inputStr)//构造方式传入初始文本
- {
- InitializeComponent();
- TextStr = inputStr;
- tbValue.Text = inputStr;
- tbValue.Focus();
- tbValue.CaretIndex = inputStr.Length;
- }
- public static readonly DependencyProperty CapsProperty = DependencyProperty.Register(
- "Caps", typeof(bool), typeof(KeyboardControl), new PropertyMetadata(default(bool)));
- public bool Caps
- {
- get { return (bool)GetValue(CapsProperty); }
- set { SetValue(CapsProperty, value); }
- }
- private void Button_Click(object sender, RoutedEventArgs e)
- {
- Button button = (Button)sender;
- if (TextIndex == 0)
- {
- tbValue.Text += (string)button.Content;
- }
- else
- {
- tbValue.Text = tbValue.Text.Insert(TextIndex, (string)button.Content);
- }
- }
- private void tbValue_TextChanged(object sender, RoutedEventArgs e)
- {
- TextBox textBox = (TextBox)sender;
- TextIndex = textBox.CaretIndex;
- }
- private void ClearButton_Click(object sender, RoutedEventArgs e)
- {
- tbValue.Text = "";
- }
- private void DELButton_Click(object sender, RoutedEventArgs e)
- {
- if (tbValue.Text.Length > 0)
- {
- if (TextIndex == 0 && tbValue.Text.Length >= 1)
- {
- tbValue.Text = tbValue.Text.Remove(tbValue.Text.Length - 1, 1);
- }
- else if (TextIndex > 0)
- {
- tbValue.Text = tbValue.Text.Remove(TextIndex - 1, 1);
- }
- }
- }
- private void OKButton_Click(object sender, RoutedEventArgs e)
- {
- TextStr = tbValue.Text;
- DialogResult = true;
- Close();
- }
- private void CancelButton_Click(object sender, RoutedEventArgs e)
- {
- DialogResult = false;
- Close();
- }
- private void CapsButton_Click(object sender, RoutedEventArgs e)
- {
- Caps = !Caps;
- }
- }
复制代码Xaml代码中用到了一个大小写的转换类:
- public class CapsConverter : IValueConverter
- {
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if (parameter == null)
- {
- return "";
- }
- if (value == null)
- {
- return parameter.ToString();
- }
- if (value is bool b)
- {
- return b ? parameter.ToString().ToUpper() : parameter.ToString().ToLower();
- }
- else
- {
- return parameter.ToString();
- }
- }
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- throw new NotImplementedException();
- }
- }
复制代码三 TouchTextBox 定义一个TouchTextBox的分部类。 - public partial class TouchTextBox
- {
- private Control hostControl;
- //OnClick方法调用时,通过Window.ShowDialog方法,打开KeyboardControl
- public void OnClick(object sender, MouseButtonEventArgs e)
- {
- if (sender is TextBox textBox)
- {
- hostControl = textBox;
- //计算KeyboardControl的位置,弹出KeyboardControl
- var text = Show(textBox.Text, textBox);
- //KeyboardControl关闭后,获取其文本值,赋值给TextBox
- if (!string.IsNullOrEmpty(text))
- {
- textBox.Text = text;
- }
- else
- {
- textBox.Text = string.Empty;
- }
- }
- }
- private string Show(string initValue, object sender = null)
- {
- var keyboard = new KeyboardControl(initValue);
- SetPosition(keyboard);
- bool result = keyboard.ShowDialog().Value;
- if (result)
- {
- return keyboard.TextStr;
- }
- else
- {
- return string.Empty;
- }
- }
- private void SetPosition(Window window)
- {
- Point point = hostControl.PointFromScreen(new Point(0.0, 0.0));
- double width = SystemParameters.WorkArea.Width;
- double height = SystemParameters.WorkArea.Height;
- if (-point.Y + hostControl.ActualHeight + 5.0 + window.Height < height)
- {
- window.Top = -point.Y + hostControl.ActualHeight + 5.0;
- }
- else
- {
- window.Top = -point.Y - window.Height - 5.0;
- }
- if (-point.X + window.Width < width)
- {
- window.Left = -point.X;
- }
- else
- {
- window.Left = -point.X - (window.Width - hostControl.ActualWidth);
- }
- }
- }
复制代码添加一个名为TouchTextBox的资源字典。
- <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- x:Class="WpfApp1.TouchTextBox">
- <Style x:Key="TouchTextBox" TargetType="{x:Type TextBox}">
- <EventSetter Event="PreviewMouseLeftButtonDown" Handler="OnClick" />
- </Style>
- </ResourceDictionary>
复制代码四 效果展示 在App.Xaml中引入TouchTextBox.Xaml资源。 - <Application x:Class="WpfApp1.App"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:local="clr-namespace:WpfApp1"
- StartupUri="MainWindow.xaml">
- <Application.Resources>
- <ResourceDictionary>
- <ResourceDictionary.MergedDictionaries>
- <ResourceDictionary Source="/WpfApp1;component/TouchTextBox.xaml" />
- </ResourceDictionary.MergedDictionaries>
- </ResourceDictionary>
- </Application.Resources>
- </Application>
复制代码MainWindow界面代码:
- <Window x:Class="WpfApp1.MainWindow"
- 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"
- Title="MainWindow" Height="800" Width="1200">
- <StackPanel>
- <TextBox Text="Pop up the keyboard after touching" Width="400" HorizontalAlignment="Left"
- FontSize="18" Margin="20,20"
- Style="{StaticResource TouchTextBox}"/>
- </StackPanel>
- </Window>
复制代码设置TextBox的Style为TouchTextBox,则该TextBox实现了自带触控键盘的效果。
|