2012-10-19 29 views
3

在C#Windows.Forms中,我想攔截組合框的paste-windowmessage。因爲這不能通過重寫組合框的WndProc方法來工作,因爲我需要重寫組合框內的文本框的WndProc,所以我決定創建一個NativeWindow類型的自定義類來覆蓋WndProc。當組合框柄被破壞時,我分配柄並釋放它。但是,當調用組合框的Dispose時,問題是我得到一個InvalidOperationException異常,說發生了無效的跨線程操作,並且組合框是從其創建線程以外的線程訪問的。任何想法在這裏出了什麼問題?使用NativeWindow for ComboBox導致Dispose方法中的異常

在下面你會看到,我的課怎麼看起來像:

public class MyCustomComboBox : ComboBox 
{ 
    private WinHook hook = null; 

    public MyCustomComboBox() 
     : base() 
    { 
     this.hook = new WinHook(this); 
    } 

    private class WinHook : NativeWindow 
    { 
     public WinHook(MyCustomComboBox parent) 
     { 
      parent.HandleCreated += new EventHandler(this.Parent_HandleCreated); 
      parent.HandleDestroyed += new EventHandler(this.Parent_HandleDestroyed); 
     } 

     protected override void WndProc(ref Message m) 
     { 
      // do something 

      base.WndProc(ref m); 
     } 

     private void Parent_HandleCreated(object sender, EventArgs e) 
     { 
      MyCustomComboBox cbx = (MyCustomComboBox)sender; 

      this.AssignHandle(cbx.Handle); 
     } 

     private void Parent_HandleDestroyed(object sender, EventArgs e) 
     { 
      this.ReleaseHandle(); 
     } 
    } 
} 

回答

4

每漢斯的建議,我修改爲使用CB_GETCOMBOBOXINFO從他自己的一個例子的代碼。

public class PastelessComboBox : ComboBox { 

    private class TextWindow : NativeWindow { 
     [StructLayout(LayoutKind.Sequential)] 
     private struct RECT { 
     public int Left; 
     public int Top; 
     public int Right; 
     public int Bottom; 
     } 

     private struct COMBOBOXINFO { 
     public Int32 cbSize; 
     public RECT rcItem; 
     public RECT rcButton; 
     public int buttonState; 
     public IntPtr hwndCombo; 
     public IntPtr hwndEdit; 
     public IntPtr hwndList; 
     } 

     [DllImport("user32.dll", EntryPoint = "SendMessageW", CharSet = CharSet.Unicode)] 
     private static extern IntPtr SendMessageCb(IntPtr hWnd, int msg, IntPtr wp, out COMBOBOXINFO lp); 

     public TextWindow(ComboBox cb) { 
     COMBOBOXINFO info = new COMBOBOXINFO(); 
     info.cbSize = Marshal.SizeOf(info); 
     SendMessageCb(cb.Handle, 0x164, IntPtr.Zero, out info); 
     this.AssignHandle(info.hwndEdit); 
     } 

     protected override void WndProc(ref Message m) { 
     if (m.Msg == (0x0302)) { 
      MessageBox.Show("No pasting allowed!"); 
      return; 
     } 
     base.WndProc(ref m); 
     } 
    } 

    private TextWindow textWindow; 

    protected override void OnHandleCreated(EventArgs e) { 
     textWindow = new TextWindow(this); 
     base.OnHandleCreated(e); 
    } 

    protected override void OnHandleDestroyed(EventArgs e) { 
     textWindow.ReleaseHandle(); 
     base.OnHandleDestroyed(e); 
    } 

    } 
+1

Iffy代碼,你迫使在構造函數中創建本地窗口。改爲改寫OnHandleCreated()。請注意,在本機窗口重新創建時它可以運行多次,因此它也可以正確處理。獲取文本框句柄的最佳方式是CB_GETCOMBOBOXINFO。 –

+0

非常感謝您的解決方案,現在終於有效了!我的第一種方法幾乎是一樣的,真​​奇怪,爲什麼它不工作... – user1225775

+0

我現在發現了什麼是我的代碼問題:唯一真正的區別是,我也覆蓋了OnHandleDestroyed方法的組合框。在那裏,我在NativeWindow上調用了ReleaseHandle。只要ReleaseHandle的這一行在代碼中,當處理被調用時,我會得到異常。爲什麼在這種情況下不允許調用ReleaseHandle? – user1225775

相關問題