2011-01-27 3 views
2

콤보 상자 컨트롤이있는 양식이 있습니다. DropDown에 드롭 다운 스타일 속성을 선택했습니다. DropDown Width를 250으로 설정했습니다. 자동 완료 모드를 설정하고 listitems에 자동 완성 소스를 설정했습니다. 내가 드롭 다운을 클릭하면 절대적으로 잘 작동합니다. 하지만 내가 입력 할 때, 자동 완성 모드는 작은 너비의 드롭 다운을 활성화합니다.콤보 상자 드롭 다운 폭을 제안합니다.

어떤 도움을 주셔서 감사합니다. 나는 목록 항목을 제대로 볼 수 있도록 코드를 통해 자동 완료 드롭 다운 너비를 늘리는 방법을 알고 싶다. C#을 사용하고 있습니다.

나는 몇 달 전에이 질문을했지만 적절한 답변을 얻지 못했습니다. 지금 고객이 그것을 원한다 : ( ??

답변

5
using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Drawing; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Windows.Forms; 

/// <summary> 
/// Represents an ComboBox with additional properties for setting the 
/// size of the AutoComplete Drop-Down window. 
/// </summary> 
public class ComboBoxEx : ComboBox 
{ 
private int acDropDownHeight = 106; 
private int acDropDownWidth = 170; 


//<EditorBrowsable(EditorBrowsableState.Always), _ 

[Browsable(true), Description("The width, in pixels, of the auto complete drop down box"), DefaultValue(170)] 
public int AutoCompleteDropDownWidth 
{ 
    get { return acDropDownWidth; } 

    set { acDropDownWidth = value; } 
} 


//<EditorBrowsable(EditorBrowsableState.Always), _ 

[Browsable(true), Description("The height, in pixels, of the auto complete drop down box"), DefaultValue(106)] 
public int AutoCompleteDropDownHeight 
{ 
    get { return acDropDownHeight; } 

    set { acDropDownHeight = value; } 
} 


protected override void OnHandleCreated(EventArgs e) 
{ 
    base.OnHandleCreated(e); 

    ACWindow.RegisterOwner(this); 
} 

#region Nested type: ACWindow 

/// <summary> 
/// Provides an encapsulation of an Auto complete drop down window 
/// handle and window proc. 
/// </summary> 
private class ACWindow : NativeWindow 
{ 
    private static readonly Dictionary<IntPtr, ACWindow> ACWindows; 

    #region "Win API Declarations" 

    private const UInt32 WM_WINDOWPOSCHANGED = 0x47; 

    private const UInt32 WM_NCDESTROY = 0x82; 


    private const UInt32 SWP_NOSIZE = 0x1; 

    private const UInt32 SWP_NOMOVE = 0x2; 

    private const UInt32 SWP_NOZORDER = 0x4; 

    private const UInt32 SWP_NOREDRAW = 0x8; 

    private const UInt32 SWP_NOACTIVATE = 0x10; 


    private const UInt32 GA_ROOT = 2; 
    private static readonly List<ComboBoxEx> owners; 


    [DllImport("user32.dll")] 
    private static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam); 


    [DllImport("user32.dll")] 
    private static extern IntPtr GetAncestor(IntPtr hWnd, UInt32 gaFlags); 


    [DllImport("kernel32.dll")] 
    private static extern int GetCurrentThreadId(); 


    [DllImport("user32.dll")] 
    private static extern void GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); 


    [DllImport("user32.dll")] 
    private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, 
              uint uFlags); 


    [DllImport("user32.dll")] 
    private static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); 

    #region Nested type: EnumThreadDelegate 

    private delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam); 

    #endregion 

    #region Nested type: RECT 

    [StructLayout(LayoutKind.Sequential)] 
    private struct RECT 
    { 
     public readonly int Left; 

     public readonly int Top; 

     public readonly int Right; 

     public readonly int Bottom; 


     public Point Location 
     { 
      get { return new Point(Left, Top); } 
     } 
    } 

    #endregion 

    #endregion 

    private ComboBoxEx owner; 

    static ACWindow() 
    { 
     ACWindows = new Dictionary<IntPtr, ACWindow>(); 

     owners = new List<ComboBoxEx>(); 
    } 


    /// <summary> 
    /// Creates a new ACWindow instance from a specific window handle. 
    /// </summary> 
    private ACWindow(IntPtr handle) 
    { 
     AssignHandle(handle); 
    } 


    /// <summary> 
    /// Registers a ComboBoxEx for adjusting the Complete Dropdown window size. 
    /// </summary> 
    public static void RegisterOwner(ComboBoxEx owner) 
    { 
     if ((owners.Contains(owner))) 
     { 
      return; 
     } 

     owners.Add(owner); 

     EnumThreadWindows(GetCurrentThreadId(), EnumThreadWindowCallback, IntPtr.Zero); 
    } 


    /// <summary> 
    /// This callback will receive the handle for each window that is 
    /// associated with the current thread. Here we match the drop down window name 
    /// to the drop down window name and assign the top window to the collection 
    /// of auto complete windows. 
    /// </summary> 
    private static bool EnumThreadWindowCallback(IntPtr hWnd, IntPtr lParam) 
    { 
     if ((GetClassName(hWnd) == "Auto-Suggest Dropdown")) 
     { 
      IntPtr handle = GetAncestor(hWnd, GA_ROOT); 


      if ((!ACWindows.ContainsKey(handle))) 
      { 
       ACWindows.Add(handle, new ACWindow(handle)); 
      } 
     } 

     return true; 
    } 


    /// <summary> 
    /// Gets the class name for a specific window handle. 
    /// </summary> 
    private static string GetClassName(IntPtr hRef) 
    { 
     var lpClassName = new StringBuilder(256); 

     GetClassName(hRef, lpClassName, 256); 

     return lpClassName.ToString(); 
    } 


    /// <summary> 
    /// Overrides the NativeWindow's WndProc to handle when the window 
    /// attributes changes. 
    /// </summary> 
    protected override void WndProc(ref Message m) 
    { 
     if ((m.Msg == WM_WINDOWPOSCHANGED)) 
     { 
      // If the owner has not been set we need to find the ComboBoxEx that 

      // is associated with this dropdown window. We do it by checking if 

      // the upper-left location of the drop-down window is within the 

      // ComboxEx client rectangle. 

      if ((owner == null)) 
      { 
       Rectangle ownerRect = default(Rectangle); 

       var acRect = new RECT(); 

       foreach (ComboBoxEx cbo in owners) 
       { 
        GetWindowRect(Handle, ref acRect); 

        ownerRect = cbo.RectangleToScreen(cbo.ClientRectangle); 

        if ((ownerRect.Contains(acRect.Location))) 
        { 
         owner = cbo; 

         break; // TODO: might not be correct. Was : Exit For 
        } 
       } 

       owners.Remove(owner); 
      } 


      if (((owner != null))) 
      { 
       SetWindowPos(Handle, IntPtr.Zero, -5, 0, owner.AutoCompleteDropDownWidth, 
          owner.AutoCompleteDropDownHeight, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); 
      } 
     } 


     if ((m.Msg == WM_NCDESTROY)) 
     { 
      ACWindows.Remove(Handle); 
     } 


     base.WndProc(ref m); 
    } 
} 

#endregion 
} 

이 무엇을이다 나는 실제로 실제로 잘 작동한다. 답을 빨리 찾으면 좋다. :)

+0

다음은이 코드를 사용한 경험입니다. 추천 드롭 다운의 크기를 조정하지 않는 즉시 잘 작동합니다. 당신은 그렇게 할 수 없을 것입니다. –

+0

@omatrot 나는이 책을 읽는다. 그러나 그것은 내 문제를 해결했다. 필요한 크기 조정 기능을 사용하여 드롭을 넓혀야 만했다. – reggie

+0

크기 조정 문제 해결에 대한 내 대답을 참조하십시오. 나는 받아 들인 대답을 편집하려했지만 거부되었다. – Loathing

0

나쁜 디자인 결정의 일종. 정적으로 큰 크기로 설정하지 않는 이유는 무엇입니까? 항상 이벤트 중 하나를 사용하여 텍스트를 가져올 수 있습니다 폭은 다음 콤보 상자의 폭을 설정하는 것을 사용한다. 아마도의 OnPaint를? 쉬운 방법은 콤보 상자에서 상속 자신의 콤보 클래스를 만든 다음 자신이 작업을 수행 할 메소드를 오버라이드 (override) 할 수 있습니다.

+1

을 내가 제안 하락의 폭을 액세스 할 수있는 방법은 없습니다 아래로 내려 와서 드롭 다운 폭과 동일하게 설정하십시오. – reggie

+0

Visual Studio의 개체 브라우저를보고 system.windows.forms.ComboBox를보고 공개적으로 액세스 할 수있는 항목을 확인하십시오. 그렇지 않으면 콤보 상자에서 상속하고 액세스 권한이 있는지 확인하십시오. 필요할 경우 반사경을 사용하십시오. –

3

이 답변은 레기의 swer.

는 사용자가 자동 ​​완성 드롭 다운의 크기를 조정할 수 있도록하려면, 다음 WndProc 메서드 내부에 다음 코드를 추가합니다

private const int WM_SIZING = 0x214; 

     if (m.Msg == WM_SIZING) { 
      if (owner != null) { 
       RECT rr = (RECT) Marshal.PtrToStructure(m.LParam, typeof(RECT)); 
       owner.acDropDownWidth = (rr.Right - rr.Left); 
       owner.acDropDownHeight = (rr.Bottom - rr.Top); 
      } 
     } 
관련 문제