2014-04-02 5 views
0

현재 제안 드롭 다운을 내 자신의 것으로 대체하는 ComboBox를 작성하고 있습니다. 이를 위해 목록 상자로 채울 ToolStripDropDown을 만듭니다. 이 목록 상자는 사용자가 콤보 상자 텍스트 필드에 텍스트를 입력 할 때 업데이트됩니다.Winforms : ToolStripDropDown으로 AutoClose를 에뮬레이트하는 방법

내 문제는 ToolStripDropDown의 AutoClose 속성을 true로 설정하면 텍스트 필드에 포커스가 있어도 ToolStripDropDown이 키보드 메시지를 포함한 많은 메시지를 "훔친다"는 것입니다.

AutoClose 속성을 false로 설정하면 모든 것이 정상적으로 작동합니다. 그러나 사용자가 콤보 외부를 클릭하면 드롭 다운이 닫히지 않습니다.

나는 내 자신의 "AutoClose"에 대해 궁금해했지만 어떻게 구현해야할지 모르겠습니다. 어떻게하는지에 대한 아이디어가 있습니까?

+0

흠, 어쩌면 당신은 또한 초점을 제어하거나 – DJmRek

+0

내가 그것을 시도했습니다 (윈폼은이 같은) 당신의 콤보 상자에 대한 "KeyPreview"를 만들 수 있지만 그렇지 않습니다 : 나는 다음과 같은 방법으로 자신의 코드를 적용했습니다 작업. 나는 또한 모든 WM_KEYDOWN, WM_KEYUP, WM_CHAR 메시지를 캡쳐하여 드롭 다운으로 보내고 (SendMessage를 사용하여) 콤보의 편집 컨트롤로 다시 보냈지 만 작동하지 않습니다. –

+0

정말 간단하고 어쩌면 더러운 해결책이 있습니다 :'ComboBox.LostFocus -> Toolstripdropdown.Close()'는 작동하지만 아직 테스트하지 않았습니다. 간단한 "AutoClose"라고 생각합니다. – DJmRek

답변

1

해결책을 찾았습니다. ToolStripManager 코드 (감사합니다 ReSharper!)를 보면 AutoClose가 true로 설정된 경우 관리자가 사용자가 드롭 다운 바깥을 클릭 할 때를 감지하기 위해 응용 프로그램 메시지를 모니터링하고 있음을 발견했습니다.

class MyComboBox : ComboBox, IMessageFilter 
{ 
     private ToolStripDropDown m_dropDown; 

     MyComboBox() 
     { 
      ... 
      Application.AddMessageFilter(this); 
      ... 
     } 

     protected override void Dispose(bool disposing) 
     { 
      ... 
      Application.RemoveMessageFilter(this); 
      base.Dispose(disposing); 
     } 


     private const int WM_LBUTTONDOWN = 0x0201; 
     private const int WM_RBUTTONDOWN = 0x0204; 
     private const int WM_MBUTTONDOWN = 0x0207; 
     private const int WM_NCLBUTTONDOWN = 0x00A1; 
     private const int WM_NCRBUTTONDOWN = 0x00A4; 
     private const int WM_NCMBUTTONDOWN = 0x00A7; 

     [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] 
     [ResourceExposure(ResourceScope.None)] 
     public static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, [In, Out] ref Point pt, int cPoints); 

     public bool PreFilterMessage(ref Message m) 
     { 
      if (m_dropDown.Visible) 
      { 
       switch (m.Msg) 
       { 
        case WM_LBUTTONDOWN: 
        case WM_RBUTTONDOWN: 
        case WM_MBUTTONDOWN: 
        case WM_NCLBUTTONDOWN: 
        case WM_NCRBUTTONDOWN: 
        case WM_NCMBUTTONDOWN: 
         // 
         // When a mouse button is pressed, we should determine if it is within the client coordinates 
         // of the active dropdown. If not, we should dismiss it. 
         // 
         int i = unchecked((int)(long)m.LParam); 
         short x = (short)(i & 0xFFFF); 
         short y = (short)((i >> 16) & 0xffff); 
         Point pt = new Point(x, y); 
         MapWindowPoints(m.HWnd, m_dropDown.Handle, ref pt, 1); 
         if (!m_dropDown.ClientRectangle.Contains(pt)) 
         { 
          // the user has clicked outside the dropdown 
          pt = new Point(x, y); 
          MapWindowPoints(m.HWnd, Handle, ref pt, 1); 
          if (!ClientRectangle.Contains(pt)) 
          { 
           // the user has clicked outside the combo 
           hideDropDown(); 
          } 
         } 
         break; 
       } 
      } 
      return false; 
     } 
} 
+0

그래서 ToolStripManager가 메시지를 잡아 끌까요? OO – DJmRek

+0

네, 모든 키보드 입력을 활성 드롭 다운으로 리디렉션하는 메시지 처리 부분이 있습니다 (ToolStripManager.PreFilterMessage -> 사례 WM_KEYDOWN : 사례 WM_KEYUP : 등 ...) –

+0

안녕 Serge, 나는 같은 문제에 부딪혔다. 나는 datagridview가 내장 된 사용자 정의 다중 열 콤보 박스를 구현하고있다. 내가 자동 완성 윈도우를 완전히 잃어 버렸을 가능성이 있습니까? ... 미리 감사드립니다. – LuckyLuke82