WPF開發經驗-實現自帶觸控鍵盤的TextBox

来源:https://www.cnblogs.com/wwwen/archive/2022/10/01/16747668.html
-Advertisement-
Play Games

一 引入 項目有個新需求,當點擊或觸碰TextBox時,基於TextBox的相對位置,彈出一個自定義的Keyboard,如下圖所示: 二 KeyboardControl 先實現一個自定義的KeyboardControl,它繼承自Window。 Xaml代碼如下: <Window x:Class="W ...


一 引入

項目有個新需求,當點擊或觸碰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>
View Code

 後臺代碼如下:

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;
    }
}
View Code

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();
    }
}
View Code

 

三 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);
        }
    }
}
View Code

添加一個名為TouchTextBox的資源字典。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    x:Class=
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 相信在大部分的web項目中都會有導出導入Excel的需求,今天我們就來看看如何用Java代碼去實現 用POI導出Excel表格。 一、pom引用 pom文件中,添加以下依賴 查看代碼 <!--Excel工具--> <dependency> <groupId>org.apache.poi</group ...
  • 總結: LinkedList繼承自List,具備有序性 LinkedList繼承自Deque,具備鏈表關聯性 LinkedList集合進行增刪改查操作底層實際是操作Node節點的前後鏈接關係 LinkedList進行增刪操作時,僅需要操作節點的前後鏈接關係,因此效率較ArrayList高 Linke ...
  • python中使用[]來截取字元串,語法: 字元串[起始位置:結束位置] 一、起始位置:結束位置 先看幾個例子: s = 'python' print(s) #輸出 python 直接輸出字元串 #從前面截取 print(s[1]) #輸出 y 根據下標取字元 print(s[:]) #輸出 pyt ...
  • 在開發過程中,像側邊欄這種功能的版塊,我們在很多頁面都需要使用到的時候,我們則需要在視圖函數中書寫重覆的代碼,這樣很繁瑣,我們可以將側邊欄製成inclusion_tag,後面我們需要用到側邊欄功能時,只需要導入即可! 將側邊欄製成inclusion_tag的步驟: 1.在應用下創建一個名字必須叫te ...
  • 2022-10-01 關聯查詢: 在Django項目中使用ORM模式設置表後,進行關聯查詢,即兩個表直接有聯繫的查詢。 方式: 可以通過主表查詢從表,也可以通過從表查詢主表。 方式一實例: (1)查詢編號為1的圖書中的人物 前提環境,進入pycharm,進入虛擬環境、進入shell環境。 首先,需要 ...
  • 在本人前一篇博文`《驅動開發:通過ReadFile與內核層通信》`詳細介紹瞭如何使用應用層`ReadFile`系列函數實現內核通信,本篇將繼續延申這個知識點,介紹利用`PIPE`命名管道實現應用層與內核層之間的多次通信方法。 ...
  • 標題是個大命題,場景其實有很多很多,而且千變萬化,一個帖子很難暢聊,以後會慢慢談。說一個最常見的場景。每個員工發張NFC卡,管理者給每人分配的卡裡寫入賬號和密碼,從而實現刷卡自動登錄客戶端系統。我看到這種需求的時候,做了一些研究,發現線上的免費解決方案根本就沒有,既然有需求沒雲端解決方案,我就自己做 ...
  • 簡述 類型:創建型 目的:實現對客戶端中對象族的平替。 對象族 一組對象。比如,華為的手機,筆記本,平板可以統稱為華為族。 我們藉以下案例來說說如何使用抽象工廠模式平替對象族。 優化案例 最初版 public interface Uploader { void upload(String fileN ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...