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
  • 在C#中使用SQL Server實現事務的ACID(原子性、一致性、隔離性、持久性)屬性和使用資料庫鎖(悲觀鎖和樂觀鎖)時,你可以通過ADO.NET的SqlConnection和SqlTransaction類來實現。下麵是一些示例和概念說明。 實現ACID事務 ACID屬性是事務處理的四個基本特征, ...
  • 我們在《SqlSugar開發框架》中,Winform界面開發部分往往也用到了自定義的用戶控制項,對應一些特殊的界面或者常用到的一些局部界面內容,我們可以使用自定義的用戶控制項來提高界面的統一性,同時也增強了使用的便利性。如我們Winform界面中用到的分頁控制項、附件顯示內容、以及一些公司、部門、菜單的下... ...
  • 在本篇教程中,我們學習瞭如何在 Taurus.MVC WebMVC 中進行數據綁定操作。我們還學習瞭如何使用 ${屬性名稱} CMS 語法來綁定頁面上的元素與 Model 中的屬性。通過這些步驟,我們成功實現了一個簡單的數據綁定示例。 ...
  • 是在MVVM中用來傳遞消息的一種方式。它是在MVVMLight框架中提供的一個實現了IMessenger介面的類,可以用來在ViewModel之間、ViewModel和View之間傳遞消息。 Send 接受一個泛型參數,表示要發送的消息內容。 Register 方法用於註冊某個對象接收消息。 pub ...
  • 概述:在WPF中,通過EventHandler可實現基礎和高級的UI更新方式。基礎用法涉及在類中定義事件,併在UI中訂閱以執行更新操作。高級用法藉助Dispatcher類,確保在非UI線程上執行操作後,通過UI線程更新界面。這兩種方法提供了靈活而可靠的UI更新機制。 在WPF(Windows Pre ...
  • 概述:本文介紹了在C#程式開發中如何利用自定義擴展方法測量代碼執行時間。通過使用簡單的Action委托,開發者可以輕鬆獲取代碼塊的執行時間,幫助優化性能、驗證演算法效率以及監控系統性能。這種通用方法提供了一種便捷而有效的方式,有助於提高開發效率和代碼質量。 在軟體開發中,瞭解代碼執行時間是優化程式性能 ...
  • 概述:Cron表達式是一種強大的定時任務調度工具,通過配置不同欄位實現靈活的時間規定。在.NET中,Quartz庫提供了簡便的方式配置Cron表達式,實現精準的定時任務調度。這種靈活性和可擴展性使得開發者能夠根據需求輕鬆地制定和管理定時任務,例如每天備份系統日誌或其他重要操作。 Cron表達式詳解 ...
  • 概述:.NET提供多種定時器,如System.Windows.Forms.Timer適用於UI,System.Web.UI.Timer用於Web,System.Diagnostics.Timer用於性能監控,System.Threading.Timer和System.Timers.Timer用於一般 ...
  • 問題背景 有同事聯繫我說,在生產環境上,訪問不了我負責的common服務,然後我去檢查common服務的health endpoint, 沒問題,然後我問了下異常,timeout導致的System.OperationCanceledException。那大概率是客戶端的問題,會不會是埠耗盡,用ne ...
  • 前言: 在本篇 Taurus.MVC WebMVC 入門開發教程的第四篇文章中, 我們將學習如何實現數據列表的綁定,通過使用 List<Model> 來展示多個數據項。 我們將繼續使用 Taurus.Mvc 命名空間,同時探討如何在視圖中綁定並顯示一個 Model 列表。 步驟1:創建 Model ...