2014-07-24 36 views
0

我有一个包含10个文本框的小表单,我将它们设置为正确的Tab键顺序,这是我希望它们选中的方式。我想知道是否有办法设置文本框,以便它们不能被选中进行编辑,除非它们被选中。即...我不希望最终用户能够点击文本框来编辑它们,我只希望它们可以通过Tabbing进行编辑。文本框不可点击但可编辑

+7

请问以这种方式控制用户体验的东西是否会吸引你?看起来像一个奇怪的要求。 –

+0

如果用户计算机中的tab键出现故障,该怎么办:p –

+0

订阅“Click”事件并在发射时聚焦另一个控件会怎样?另外,我想知道和@MikeCheel一样的东西。 – Jashaszun

回答

6

这应该做的伎俩

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); 
    } 
} 

窗口消息枚举可以发现here


如何做没有继承 TextBox

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 
} 
+0

这真的很难看 –

+1

@MatinLotfaliee不要幼稚。 –

+0

那么,我相信继承和使用Windows消息是丑陋的,当他可以做一些简单的事件。 –

0

设置所有文本框'启用属性为虚假除第一个。在TextChanged事件中,检查它是否为文本为空或不是。如果不是空的,启用下一个文本框等等...

+0

这可能是可行的,我会看到如果我能从你的建议中得出一个工作解决方案。谢谢。 – roadmaster

+1

这不是一个真正的答案,因为它对文本的相关性作出了空白或不是没有问题的假设。但也许它有助于... – TaW

0

你也可以试试这个与输入事件的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(); 
    } 
+0

这真的很难看 –

+2

这不是一个真正的答案,因为它可以假设文本的相关性为空或者不在问题中。但也许它有帮助.. – TaW

1

这里有一个类似的方法是什么斯利拉姆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; 
    } 

} 
+0

我正要添加类似的使用'IMessageFilter',现在没有必要它+1 :) –