Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 文本框不可单击,但可编辑_C#_Winforms_Textbox - Fatal编程技术网

C# 文本框不可单击,但可编辑

C# 文本框不可单击,但可编辑,c#,winforms,textbox,C#,Winforms,Textbox,我有一个包含10个文本框的小表单,我将它们设置为正确的制表顺序,目前是我希望它们制表的方式。我想知道是否有一种方法可以设置文本框,这样它们就不能被选中进行编辑,除非它们被标记为。即。。。我不希望最终用户能够单击文本框来编辑它们,我只希望它们可以通过选项卡进行编辑。将所有文本框的启用属性设置为false,第一个除外。在TextChanged事件中,检查文本是否为空。如果它不是空的,启用下一个文本框,依此类推……这应该可以解决问题 public partial class PoorTextBox :

我有一个包含10个文本框的小表单,我将它们设置为正确的制表顺序,目前是我希望它们制表的方式。我想知道是否有一种方法可以设置文本框,这样它们就不能被选中进行编辑,除非它们被标记为。即。。。我不希望最终用户能够单击文本框来编辑它们,我只希望它们可以通过选项卡进行编辑。

将所有文本框的启用属性设置为false,第一个除外。在TextChanged事件中,检查文本是否为空。如果它不是空的,启用下一个文本框,依此类推……

这应该可以解决问题

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:)