C# 文本框不可单击,但可编辑
我有一个包含10个文本框的小表单,我将它们设置为正确的制表顺序,目前是我希望它们制表的方式。我想知道是否有一种方法可以设置文本框,这样它们就不能被选中进行编辑,除非它们被标记为。即。。。我不希望最终用户能够单击文本框来编辑它们,我只希望它们可以通过选项卡进行编辑。将所有文本框的启用属性设置为false,第一个除外。在TextChanged事件中,检查文本是否为空。如果它不是空的,启用下一个文本框,依此类推……这应该可以解决问题C# 文本框不可单击,但可编辑,c#,winforms,textbox,C#,Winforms,Textbox,我有一个包含10个文本框的小表单,我将它们设置为正确的制表顺序,目前是我希望它们制表的方式。我想知道是否有一种方法可以设置文本框,这样它们就不能被选中进行编辑,除非它们被标记为。即。。。我不希望最终用户能够单击文本框来编辑它们,我只希望它们可以通过选项卡进行编辑。将所有文本框的启用属性设置为false,第一个除外。在TextChanged事件中,检查文本是否为空。如果它不是空的,启用下一个文本框,依此类推……这应该可以解决问题 public partial class PoorTextBox :
public partial class PoorTextBox : TextBox
{
protected override void WndProc(ref Message m)
{
if (m.Msg == (int) WM.LBUTTONDOWN)
{
return;//Eat mouse down events
}
base.WndProc(ref m);
}
}
可以找到窗口消息枚举。
如何在不继承
文本框的情况下执行此操作
:
class EatMouseDown : NativeWindow
{
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)WM.LBUTTONDOWN)
{
return;
}
base.WndProc(ref m);
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
new EatMouseDown().AssignHandle(textBox1.Handle);//Subclass a Handle
}
如何在没有任何继承的情况下执行此操作: 清理遗漏的零件,这也很重要。这辆车可能有问题,但它能用。推荐的方法是使用继承。从.net fw src提取的必需方法
class EatMouseDown
{
public delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
#region External methods...
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetWindowLong(HandleRef hWnd, int nIndex, WndProc wndproc);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetWindowLongPtr(HandleRef hWnd, int nIndex, WndProc wndproc);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindowLong(HandleRef hWnd, int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindowLongPtr(HandleRef hWnd, int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr DefWindowProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr CallWindowProc(IntPtr wndProc, IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
#endregion
private const int GWLP_WNDPROC = -4;
private IntPtr handle;
private IntPtr originalWndProc;
private IntPtr currentWndProc;
public static IntPtr SetWindowLongHelper(HandleRef hWnd, int nIndex, WndProc wndProc)
{
return IntPtr.Size == 4
? SetWindowLong(hWnd, nIndex, wndProc)
: SetWindowLongPtr(hWnd, nIndex, wndProc);
}
public static IntPtr GetWindowLongHelper(HandleRef hWnd, int nIndex)
{
return IntPtr.Size == 4
? GetWindowLong(hWnd, nIndex)
: GetWindowLongPtr(hWnd, nIndex);
}
internal void SubclassHandle(IntPtr handle)
{
this.handle = handle;
this.originalWndProc = GetWindowLongHelper(new HandleRef(this, handle), GWLP_WNDPROC);
SetWindowLongHelper(new HandleRef(this, handle), GWLP_WNDPROC, new WndProc(this.Callback));
this.currentWndProc = GetWindowLongHelper(new HandleRef(this, handle), GWLP_WNDPROC);
}
private IntPtr Callback(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam)
{
var m = Message.Create(hwnd, msg, wparam, lparam);
if (m.Msg == (int)WM.LBUTTONDOWN)
{
return IntPtr.Zero;
}
return CallWindowProc(originalWndProc, hwnd, msg, wparam, lparam);
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
new EatMouseDown().SubclassHandle(textBox1.Handle);//Subclass a Handle
}
您也可以使用Enterevent foreach文本框尝试此操作
private void textBox2_Enter(object sender, EventArgs e)
{
if (textBox1.Text == "")
textBox1.Focus();
}
private void textBox3_Enter(object sender, EventArgs e)
{
if (textBox1.Text == "")
textBox1.Focus();
else
if (textBox2.Text == "")
textBox2.Focus();
}
private void textBox4_Enter(object sender, EventArgs e)
{
if (textBox1.Text == "")
textBox1.Focus();
else
if (textBox2.Text == "")
textBox2.Focus();
else
if (textBox3.Text == "")
textBox3.Focus();
}
这里有一个与Sriram Sakthivel所做的类似的方法,但是使用了IMessageFilter:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
List<TextBox> TextBoxes = new List<TextBox>();
FindTextBoxes(this, TextBoxes);
Application.AddMessageFilter(new SuppressTextBoxClicks(TextBoxes));
}
private void FindTextBoxes(Control ctl, List<TextBox> TBs)
{
foreach(Control childCtl in ctl.Controls)
{
if (childCtl is TextBox)
{
TBs.Add((TextBox)childCtl);
}
else if(childCtl.HasChildren)
{
FindTextBoxes(childCtl, TBs);
}
}
}
}
public class SuppressTextBoxClicks : IMessageFilter
{
private List<TextBox> _TextBoxes = null;
private const int WM_LBUTTONDOWN = 0x201;
public SuppressTextBoxClicks(List<TextBox> TextBoxes)
{
_TextBoxes = TextBoxes;
}
public bool PreFilterMessage(ref Message m)
{
switch (m.Msg)
{
case WM_LBUTTONDOWN:
if (_TextBoxes != null)
{
foreach(TextBox TB in _TextBoxes)
{
if (TB.Handle.Equals(m.HWnd))
{
return true;
}
}
}
break;
default:
break;
}
return false;
}
}
公共部分类表单1:表单
{
公共表格1()
{
初始化组件();
}
私有void Form1\u加载(对象发送方、事件参数e)
{
列表文本框=新列表();
FindTextBox(这是文本框);
Application.AddMessageFilter(新建SuppressTextBoxClicks(文本框));
}
专用void findtextbox(控制ctl、列表TBs)
{
foreach(控制子控件中的控制子控件)
{
如果(childCtl是文本框)
{
TBs.Add((文本框)childCtl);
}
else if(childCtl.HasChildren)
{
findtextbox(childCtl,TBs);
}
}
}
}
公共类SuppressTextBoxClicks:IMessageFilter
{
私有列表_textboxs=null;
私有常量int WM_LBUTTONDOWN=0x201;
公共抑制文本框单击(列出文本框)
{
_文本框=文本框;
}
公共bool预过滤器消息(参考消息m)
{
开关(m.Msg)
{
案例WM_LBUTTONDOWN:
如果(_textboxs!=null)
{
foreach(文本框中的文本框TB)
{
if(TB.Handle.Equals(m.HWnd))
{
返回true;
}
}
}
打破
违约:
打破
}
返回false;
}
}
我可以问一下,以这种方式控制用户体验能给您带来什么好处吗?这似乎是一个奇怪的要求。如果用户机器上的tab键出现故障怎么办:p订阅单击事件并在触发时聚焦另一个控件如何?另外,对于那些想知道原因的人来说,我想知道的是@MikeCheel.Ok,这是一件同样的事情:我首先要为我自己、我自己以及一两个朋友写这篇文章。我正在为一个在线游戏(便利工具)编写一个dps计算器。我相信使用Tab/Enter键从一个框移动到另一个框更容易、更快,而使用鼠标分别单击每个框对我来说似乎有点慢,因为大多数人本能地用鼠标按钮单击,他们可能认为不使用Tab键。这当然是我个人的喜好,如果我后来觉得没有太大的区别,我总是可以撤销它。@roadmaster,这仍然没有意义。即使文本框是可点击的,您仍然可以使用TAB键在框之间导航。@Matinlotfalie不要孩子气。@Matinlotfalie-当他有多个文本框时,您的路线就不那么漂亮或简单了。至少有了这个路由,你可以创建控件,然后再也不用担心它的外观了。@Matinlotfalie你认为你拥有的是简单的吗?虽然对我来说,真的不是。它是复杂的代码,更容易出错,需要更多的测试,违反了DRY原则,等等。顺便说一句,如果继承是一个问题,你几乎可以不用继承来完成它。@Sriram:你可以不用继承来完成它。帮我解决这个问题:怎么做?你太好了!继承窗口并不是很吸引人。这可能是可行的,我会看看是否能从你的建议中想出一个可行的解决方案。谢谢。这并不是一个真正的答案,因为它假设了文本是否为空,这不在问题中。但不管怎样,这可能会有所帮助。这并不是一个真正的答案,因为它假设文本的相关性是否为空,这不在问题中。但不管怎样,它可能会有所帮助..我正要使用IMessageFilter
添加类似的一个,现在不需要它+1:)