WPF开发--自带触控键盘的TeXTBOX实现

一 引入
项目有个新需求,当点击或触碰TextBox时,基于TextBox的相对位置,弹出一个自定义的Keyboard,如下图所示:
在这里插入图片描述

二 KeyboardControl
先实现一个自定义的KeyboardControl,它继承自Window。

Xaml代码如下:

<FrameworkElement.Resources>


<local:CapsConverter x:Key=“CapsConverter”/>

</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>

后台代码如下:
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的资源字典。


四 效果展示
在App.Xaml中引入TouchTextBox.Xaml资源。

<Application.Resources>

<ResourceDictionary.MergedDictionaries>

</ResourceDictionary.MergedDictionaries>

</Application.Resources>

MainWindow界面代码




设置TextBox的Style为TouchTextBox,则该TextBox实现了自带触控键盘的效果。

猜你喜欢

转载自blog.csdn.net/weixin_41883890/article/details/129026548
今日推荐