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
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...