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
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...