分享
 
 
 

Windows 控件限制用户输入的基本法门(.NET 篇) 选择自 FlashElf 的 Blog

王朝c#·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

/******************************************************************

Windows 控件限制用户的基本法门(.NET 篇)

VB.NET 的在下面

-------------------------------------------------------------------

本代码演示 控制用户的输入的基本方式(屏蔽非数字字符输入)

.net 下限制用户输入,看见很多人是在 键盘,或 textBox 的 TextChanged 事件里做

个人认为那样是不正确的,

1.不能限制用户的粘贴

2.严重干扰数据绑定等操作

3.有时还需要备份原始数据进行还原

其实正确的限制输入的时机是在,windows 消息 WM_CHAR 触发时

但.net 恰恰没有提供这个消息的事件映射.怎么办?

提供方案两列:

1)继承TextBox 重写 WndProc 函数 (优点点oo编程的优点我不说了)

处理

if (m.Msg==WM_CHAR){

// 然后取 m.WParam 进行判断 m.WParam 就是用户输入的字符的 int 表示方式

// 如果是被限制的字符 直接 Return

//不走 base.WndProc (ref m);

}

if(m.Msg==WM_PASTE)

{

//判断剪贴板的数据是否是符合要求如果符合不做任何处理

//否则 Return 不走默然处理即可

}

base.WndProc (ref m);

2)利用API SetWindowLong 替换默认的处理消息的函数进行处理

本文写的就是这种 ,演示如何声明API 而且本方法很多语言都可以使用,

但如果程序中有多个需要限制输入的控件而且相做通用类库的话

使用建议使用方案一

废话不多说了看代码吧.

*******************************************************************/

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Runtime.InteropServices;

using System.Text.RegularExpressions;

using System.Diagnostics;

namespace SETWNDPROC

{

/// <summary>

/// Form1 的摘要说明。

/// </summary>

public class Form1 : System.Windows.Forms.Form

{

//声明一个委托

public delegate IntPtr NewWndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

//API 具体帮助请察看 MSDN 或到 MS 网站上去找

[DllImport("user32.dll", CharSet=CharSet.Auto)]

public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, NewWndProc wndproc);

[DllImport("user32.dll", CharSet=CharSet.Auto)]

public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

//没用到

[DllImport("user32.dll", CharSet=CharSet.Auto)]

public static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);

[DllImport("user32.dll", CharSet=CharSet.Auto)]

public static extern IntPtr CallWindowProc(IntPtr wndProc, IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

//SetWindowLong 用的常数,不知道什么意识的去看 msdn吧

public const int GWL_WNDPROC = -4;

//右键菜单消息

public const int WM_CONTEXTMENU = 0x007b;

//粘贴消息

public const int WM_PASTE = 0x0302;

//输入字符消息(键盘输入的,输入法输入的好像不是这个消息)

public const int WM_CHAR = 0x0102;

//一定要声明为实列变量否则,局部变量发送给API后很容易被_u71 ?C 回收,

//会出现根本无法捕获的异常

private NewWndProc wpr=null;

//备份的默然处理函数

private IntPtr oldWndProc=IntPtr.Zero;

private System.Windows.Forms.TextBox textBox1;

/// <summary>

/// 必需的设计器变量。

/// </summary>

private System.ComponentModel.Container components = null;

public Form1()

{

//

// Windows 窗体设计器支持所必需的

//

InitializeComponent();

//

// TODO: 在 InitializeComponent_u-29693 ?用后添加任何构造函数代码

//

}

/// <summary>

/// 清理所有正在使用的资源。

/// </summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

#region Windows 窗体设计器生成的代码

/// <summary>

/// 设计器支持所需的方法 - 不要使用代码编辑器修改

/// 此方法的内容。

/// </summary>

private void InitializeComponent()

{

this.textBox1 = new System.Windows.Forms.TextBox();

this.SuspendLayout();

//

// textBox1

//

this.textBox1.Location = new System.Drawing.Point(32, 16);

this.textBox1.Name = "textBox1";

this.textBox1.TabIndex = 0;

this.textBox1.Text = "555";

this.textBox1.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;

//

// Form1

//

this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);

this.ClientSize = new System.Drawing.Size(152, 53);

this.Controls.Add(this.textBox1);

this.Name = "Form1";

this.Text = "Form1";

this.Load += new System.EventHandler(this.Form1_Load);

this.Closed += new System.EventHandler(this.Form1_Closed);

this.ResumeLayout(false);

}

#endregion

/// <summary>

/// 应用程序的主入口点。

/// </summary>

[STAThread]

static void Main()

{

Application.Run(new Form1());

}

private IntPtr TextBoxWndProc(IntPtr_u104 ?Wnd, int msg, IntPtr wParam, IntPtr lParam)

{

IntPtr returnVar=IntPtr.Zero;

switch (msg)

{

//粘贴消息包括 Ctrl+V Or 右键菜单粘贴

case WM_PASTE:

//取剪贴板对象

IDataObject iData = Clipboard.GetDataObject();

//判断是否是Text

if(iData.GetDataPresent(DataFormats.Text))

{

//取数据

string str;

str = (String)iData.GetData(DataFormats.Text);

/*

如果需要正负号,先要判断TextBox 上光标的位置

如果光标在最前面可以用这个,^(((\+|-)\d)?\d*)$

下面的 WM_CHAR 也要做相应变化

*/

//如果是数字(可以粘贴跳出)

if (Regex.IsMatch(str,@"^(\d{1,})$"))

break;

}

//不可以粘贴

return (IntPtr)0;

case WM_CHAR:

int keyChar=wParam.ToInt32();

Debug.WriteLine(keyChar);

bool charOk=(keyChar>47 && keyChar<58) || //数字

keyChar==8 || //退格

keyChar==3 || keyChar==22 || keyChar==24;//拷贝,粘贴,剪切

//如果不是需要的的字符 wParam 改为字符 0

//return (IntPtr)0; 也行不过没有禁止输入的 键盘音

if (!charOk) wParam=(IntPtr)0;

break;

//禁止右键菜单(如果需要的话)

//case WM_CONTEXTMENU:

//return (IntPtr)0;

}

//回调备份的默认处理的函数

returnVar= CallWindowProc(oldWndProc,hWnd,msg,wParam,lParam);

return returnVar;

}

private void Form1_Load(object sender, System.EventArgs e)

{

this.Show();

//备份默认处理函数

//oldWndProc=GetWindowLong(textBox1.Handle,GWL_WNDPROC);

//实列化委托(这里就是回调函数)

wpr= new NewWndProc(this.TextBoxWndProc);

//替换控件的默认处理函数(并且返回原始的 默认处理函数,是一个函数指针的地质)

oldWndProc=SetWindowLong(textBox1.Handle,GWL_WNDPROC,wpr);

}

private void Form1_Closed(object sender, System.EventArgs e)

{

//还原默认处理函数

if (!oldWndProc.Equals(IntPtr.Zero))

SetWindowLong(textBox1.Handle,GWL_WNDPROC,oldWndProc);

}

}

}

FlashElf 2004年10月31日16:25:21

'/******************************************************************

' Windows 控件限制用户输入的基本法门(.NET 篇) For VB.NET

' C# 篇

' http://blog.csdn.net/flashelf/archive/2004/10/31/161024.aspx

'

'-------------------------------------------------------------------

' 本代码演示 控制用户的输入的基本方式(屏蔽非数字字符输入)

' .net 下限制用户输入,看见很多人是在 键盘,或 textBox 的 TextChanged 事件里做

' 个人认为那样是不正确的,

' 1.不能限制用户的粘贴

' 2.严重干扰数据绑定等操作

' 3.有时还需要备份原始数据进行还原

' 其实正确的限制输入的时机是在,windows 消息 WM_CHAR 触发时

' 但.net 恰恰没有提供这个消息的事件映射.怎么办?

' 提供方案两列:

' 1)继承TextBox 重写 WndProc 函数 (优点点oo编程的优点我不说了)

' 处理

' if (m.Msg==WM_CHAR){

' // 然后取 m.WParam 进行判断 m.WParam 就是用户输入的字符的 int 表示方式

' // 如果是被限制的字符 直接 Return

' //不走 base.WndProc (ref m);

' }

' if(m.Msg==WM_PASTE)

' {

' //判断剪贴板的数据是否是符合要求如果符合不做任何处理

' //否则 Return 不走默然处理即可

' }

' base.WndProc (ref m);

' 2)利用API SetWindowLong 替换默认的处理消息的函数进行处理

' 本文写的就是这种 ,演示如何声明API 而且本方法很多语言都可以使用,

' 但如果程序中有多个需要限制输入的控件而且相做通用类库的话

' 使用建议使用方案一

'废话不多说了看代码吧.

'*******************************************************************/

Imports System.Runtime.InteropServices

Imports System.Text.RegularExpressions

Public Class Form1

Inherits System.Windows.Forms.Form

'声明一个委托

Public Delegate Function NewWndProc(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr

'声明 N 个API

<DllImport("user32.dll", CharSet:=CharSet.Auto)> _

Public Shared Function CallWindowProc(ByVal wndProc As IntPtr, ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr

End Function

<DllImport("user32.dll", CharSet:=CharSet.Auto)> _

Public Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal wndproc As NewWndProc) As IntPtr

End Function

<DllImport("user32.dll", CharSet:=CharSet.Auto)> _

Public Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As IntPtr) As IntPtr

End Function

'要用的常数

Public Const GWL_WNDPROC As Integer = -4

'输入字符消息(键盘输入的,输入法输入的好像不是这个消息)

Public Const WM_CHAR As Integer = 258

'右键菜单消息

Public Const WM_CONTEXTMENU As Integer = 123

'粘贴消息

Public Const WM_PASTE As Integer = 770

Private wpr As NewWndProc

Private oldWndProc As IntPtr

#Region " Windows 窗体设计器生成的代码 "

Public Sub New()

MyBase.New()

'该调用是 Windows 窗体设计器所必需的。

InitializeComponent()

'在 InitializeComponent() 调用之后添加任何初始化

End Sub

'窗体重写 dispose 以清理组件列表。

Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

If disposing Then

If Not (components Is Nothing) Then

components.Dispose()

End If

End If

MyBase.Dispose(disposing)

End Sub

'Windows 窗体设计器所必需的

Private components As System.ComponentModel.IContainer

'注意: 以下过程是 Windows 窗体设计器所必需的

'可以使用 Windows 窗体设计器修改此过程。

'不要使用代码编辑器修改它。

Friend WithEvents TextBox1 As System.Windows.Forms.TextBox

<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

Me.TextBox1 = New System.Windows.Forms.TextBox

Me.SuspendLayout()

'

'TextBox1

'

Me.TextBox1.Location = New System.Drawing.Point(24, 16)

Me.TextBox1.Name = "TextBox1"

Me.TextBox1.TabIndex = 0

Me.TextBox1.Text = ""

Me.TextBox1.TextAlign = System.Windows.Forms.HorizontalAlignment.Right

'

'Form1

'

Me.AutoScaleBaseSize = New System.Drawing.Size(6, 14)

Me.ClientSize = New System.Drawing.Size(160, 53)

Me.Controls.Add(Me.TextBox1)

Me.Name = "Form1"

Me.Text = "Form1"

Me.ResumeLayout(False)

End Sub

#End Region

Private Function TextBoxWndProc(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr

Dim returnVar As IntPtr = IntPtr.Zero

Select Case msg

Case WM_CHAR

Dim keyChar As Integer = wParam.ToInt32()

Dim charOk As Boolean = (keyChar > 47 AndAlso keyChar < 58) _

OrElse keyChar = 8 OrElse _

keyChar = 3 OrElse keyChar = 22 OrElse keyChar = 24

'如果不是需要的的字符 wParam 改为字符 0

'return (IntPtr)0; 也行不过没有禁止输入的键盘音

If Not charOk Then

wParam = IntPtr.Zero

End If

Exit Select

'粘贴消息包括 Ctrl+V Or 右键菜单粘贴

Case WM_PASTE

'取剪贴板对象

Dim obj1 As IDataObject = Clipboard.GetDataObject

'判断是否是Text

If obj1.GetDataPresent(DataFormats.Text) Then

Dim text1 As String = CType(obj1.GetData(DataFormats.Text), String)

'如果需要正负号,先要判断TextBox 上光标的位置

'如果光标在最前面可以用这个,^(((\+|-)\d)?\d*)$

'下面的 WM_CHAR 也要做相应变化

'

'如果是数字(可以粘贴跳出)

If Regex.IsMatch(text1, "^(\d{1,})$") Then

Exit Select

End If

End If

Return IntPtr.Zero

End Select

returnVar = CallWindowProc(oldWndProc, hWnd, msg, wParam, lParam)

Return returnVar

End Function

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

'//实列化委托(这里就是回调函数)

wpr = New NewWndProc(AddressOf Me.TextBoxWndProc)

'//替换控件的默认处理函数(并且返回原始的 默认处理函数,是一个函数指针的地质)

oldWndProc = SetWindowLong(TextBox1.Handle, GWL_WNDPROC, wpr)

End Sub

Private Sub Form1_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed

'还原默认处理函数

If Not oldWndProc.Equals(IntPtr.Zero) Then

SetWindowLong(TextBox1.Handle, GWL_WNDPROC, oldWndProc)

End If

End Sub

End Class

Flashelf 2004年10月31日18:00:19

作者Blog:http://blog.csdn.net/FlashElf/

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有