WPF:自定义IP地址输入框的实现

13 篇文章 2 订阅

先看效果图:

在这里插入图片描述
仿照电脑以太网属性那里的IP地址输入框设计的
在这里插入图片描述

实现的主要功能有:

1、只能输入数字、Delete、Enter、Back、Tab、左右方向键,且数字在0-255之间。
2、输入数字最多三位,超过三位自动跳转到下一个输入框;如果输入框中有数字,则全选数字。
3、Delete就正常从后面删除;Enter暂时无操作();Tab自动跳转焦点;
4、Back往前删除,如果当前输入框为空,则跳转到前面一个输入框;如果前面一个输入框有数字,则删除一位数字;左右方向键就控制光标移动。

布局

4个TextBox构成4个数字输入框,3个Label构成3个点。

布局文件

新建UserControl,布局如下:

<Grid>
    <Border Name="Border"
            BorderBrush="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Path=BorderBrush}"
            Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Path=Background}"
            BorderThickness="1"
            RenderOptions.EdgeMode="Aliased">
        <Grid Name="GridIPAddress">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="15"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="15"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="15"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <TextBox Grid.Column="0" Name="TbxIP1" HorizontalContentAlignment="Center" Background="Transparent" InputMethod.IsInputMethodEnabled="False" MaxLength="3" PreviewKeyDown="TbxIP1_PreviewKeyDown" PreviewKeyUp="TbxIP1_PreviewKeyUp" Style="{StaticResource TextBoxWithoutBorderStyle}"/>
            <TextBox Grid.Column="2" Name="TbxIP2" HorizontalContentAlignment="Center" Background="Transparent" InputMethod.IsInputMethodEnabled="False" MaxLength="3" PreviewKeyDown="TbxIP1_PreviewKeyDown" PreviewKeyUp="TbxIP1_PreviewKeyUp" Style="{StaticResource TextBoxWithoutBorderStyle}"/>
            <TextBox Grid.Column="4" Name="TbxIP3" HorizontalContentAlignment="Center" Background="Transparent" InputMethod.IsInputMethodEnabled="False" MaxLength="3" PreviewKeyDown="TbxIP1_PreviewKeyDown" PreviewKeyUp="TbxIP1_PreviewKeyUp" Style="{StaticResource TextBoxWithoutBorderStyle}"/>
            <TextBox Grid.Column="6" Name="TbxIP4" HorizontalContentAlignment="Center" Background="Transparent" InputMethod.IsInputMethodEnabled="False" MaxLength="3" PreviewKeyDown="TbxIP1_PreviewKeyDown" PreviewKeyUp="TbxIP1_PreviewKeyUp" Style="{StaticResource TextBoxWithoutBorderStyle}"/>
            <Label Grid.Column="1" Style="{StaticResource LabelDotStyle}"/>
            <Label Grid.Column="3" Style="{StaticResource LabelDotStyle}"/>
            <Label Grid.Column="5" Style="{StaticResource LabelDotStyle}"/>
        </Grid>
    </Border>
</Grid>

注意:
1、设置 InputMethod.IsInputMethodEnabled=false,禁用输入法,也就是不能中文输入,不然的话不能识别按键事件
2、PreviewKeyDownPreviewKeyUp,在按下按键之前,以及释放按键之前两个事件中处理上述的主要功能。
3、个人体会,当想输入例如数字1时,1显示在屏幕上,是发生在PreviewKeyDownPreviewKeyUp这两个事件中间的。例如输入1,在PreviewKeyDown判断是不是那些允许的按键,判断是的,那么屏幕中显示1,PreviewKeyUp判断输入1以后,要不要跳转到下一个输入框,以及数字在不在0-255之间。
4、资源文件 LabelDotStyleTextBoxWithoutBorderStyle就不贴代码了

实现代码

/// <summary>
/// 按下按键键前,判断哪些能输入
/// 只能输入数字 删除键 回车键 返回键 Tab键 左右方向键
/// 删除键、左右方向键 控制光标位置
/// </summary>
private void TbxIP1_PreviewKeyDown(object sender, KeyEventArgs e)
{
    Key key = e.Key;
    TextBox tbx = sender as TextBox;
    if ((key >= Key.D0 && key <= Key.D9) || (key >= Key.NumPad0 && key <= Key.NumPad9))
    {
    }
    else if (key == Key.Delete)
    {
    }
    else if (key == Key.Enter)
    {
    }
    else if (key == Key.Back)
    {
        // 删除光标前面的数字,如果光标前没有数字,会跳转到前面一个输入框
        // 先Focus到了前面一个输入框,再执行的删除操作,所以会删除前面输入框中的一个数字
        if (tbx.CaretIndex == 0)
        {
            SetTbxFocus(tbx, false, false);
        }
    }
    else if (key == Key.Tab)
    {
    }
    else if (key == Key.Left)
    {
        // 光标已经在当前输入框的最左边,则跳转到前面一个输入框
        if (tbx.CaretIndex == 0)
        {
            SetTbxFocus(tbx, false, false);
            // 得设置true,不然光标在前面一个输入框里也会移动一次
            // 例如前一个输入框中的数字是123,Focus后,光标在数字3右边
            // 不设置true,会移动到数字2和数字3之间
            e.Handled = true;
        }
    }
    else if (key == Key.Right)
    {
        // 光标已经在当前输入框的最右边,则跳转到后面一个输入框
        if (tbx.SelectionStart == tbx.Text.Length)
        {
            SetTbxFocus(tbx, true, false);
            // true同理
            e.Handled = true;
        }
    }
    else
    {
        // 不是上述按键,就不处理
        e.Handled = true;
    }
}
/// <summary>
/// 释放按键前,判断光标要做什么操作
/// </summary>
private void TbxIP1_PreviewKeyUp(object sender, KeyEventArgs e)
{
    Key key = e.Key;
    TextBox tbx = sender as TextBox;
    if ((key >= Key.D0 && key <= Key.D9) || (key >= Key.NumPad0 && key <= Key.NumPad9))
    {
        // 当前输入框满三个数字后
        // 跳转到后面一个输入框
        if (tbx.Text.Length == 3)
        {
            if(Int32.Parse(tbx.Text) <0 || Int32.Parse(tbx.Text) > 255)
            {
                tbx.Text = "255";
                MessageBox.Show(tbx.Text + "不是有效项。请指定一个介于0和255间的值。", "错误", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }
            SetTbxFocus(tbx, true, true);
        }
    }
    else if (key == Key.Delete)
    {
        // 无操作
    }
    else if (key == Key.Enter)
    {
        // 暂时不做操作
    }
    else if (key == Key.Back)
    {
    }
    else if (key == Key.Tab)
    {
        // 暂时不做操作
    }
    else if (key == Key.Left)
    {
    }
    else if (key == Key.Right)
    {
    }
    else
    {
        // 不是上述按键,就不处理
        e.Handled = true;
    }
}

/// <summary>
/// 设置当前输入框的前面或后面的输入框获取焦点,以及是否全选内容
/// </summary>
/// <param name="curretTbx">当前输入框</param>
/// <param name="isBack">是否是后面的输入框(false为前面的输入框)</param>
/// <param name="isSelectAll">是否全选内容</param>
private void SetTbxFocus(TextBox curretTbx, bool isBack, bool isSelectAll)
{
    // 所有的ip输入框
    List<TextBox> TbxIPList = new List<TextBox>(); 
    foreach (UIElement item in GridIPAddress.Children)
    {
        if(item.GetType() == typeof(TextBox))
        {
            TbxIPList.Add(item as TextBox);
        }
    }
    // 要聚焦的输入框
    TextBox nextTbx = null;
    // 往后
    if (isBack)
    {
        // 当前输入框是前三个,那么就取后一个输入框
        int index = TbxIPList.IndexOf(curretTbx);
        if (index <= 2)
        {
            nextTbx = TbxIPList[index + 1];
        }
    }
    // 往前
    else
    {
        // 当前输入框是后三个,那么就取前一个输入框
        int index = TbxIPList.IndexOf(curretTbx);
        if (index >= 1)
        {
            nextTbx = TbxIPList[index - 1];
        }
    }
    // 设置焦点 全选内容
    if(nextTbx != null)
    {
        nextTbx.Focus();
        if (isSelectAll)
        {
            nextTbx.SelectAll();
        }
    }
}

额,主要的解释都在注释里面了。

如何使用

在布局文件中直接引用就好啦

<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
    <Label Content="IPv4" Margin="200,0,20,0"/>
    <local:UC_IPAddress x:Name="UC_ipaddress" Width="200" Height="30" Background="White" BorderBrush="Black"/>
</StackPanel>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值