ComboBox Dropdown Position

后端 未结 1 1540
醉酒成梦
醉酒成梦 2020-11-28 14:52

I have a maximized form which has Combo-Box control (docked in top-right) with 500px Width

After trying to open the combo-box , the half of the list goe

相关标签:
1条回答
  • 2020-11-28 15:20

    Tricky problem. I could not find a good fix for this, merely a workaround. Add a new class and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form.

    The workaround is not a very good one. The problem is that the dropdown window will ignore the attempt to move it until the drop-down animation is complete. The visual effect is not great, you'll see the window drop down, then jump to the left. I don't know an other way to slap it over the head, maybe somebody else does.

    C# version:

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    public class MyComboBox : ComboBox {
      protected override void OnDropDown(EventArgs e) {
        // Is dropdown off the right side of the screen?
        Point pos = this.PointToScreen(this.Location);
        Screen scr = Screen.FromPoint(pos);
        if (scr.WorkingArea.Right < pos.X + this.DropDownWidth) {
           this.BeginInvoke(new Action(() => {
            // Retrieve handle to dropdown list
            COMBOBOXINFO info = new COMBOBOXINFO();
            info.cbSize = Marshal.SizeOf(info);
            SendMessageCb(this.Handle, 0x164, IntPtr.Zero, out info);
            // Move the dropdown window
            RECT rc;
            GetWindowRect(info.hwndList, out rc);
            int x = scr.WorkingArea.Right - (rc.Right - rc.Left);
            SetWindowPos(info.hwndList, IntPtr.Zero, x, rc.Top, 0, 0, 5);
          }));
        }
        base.OnDropDown(e);
      }
    
      // P/Invoke declarations
      private struct COMBOBOXINFO {
        public Int32 cbSize;
        public RECT rcItem, rcButton;
        public int buttonState;
        public IntPtr hwndCombo, hwndEdit, hwndList;
      }
      private struct RECT {
        public int Left, Top, Right, Bottom;
      }
      [DllImport("user32.dll", EntryPoint = "SendMessageW", CharSet = CharSet.Unicode)]
      private static extern IntPtr SendMessageCb(IntPtr hWnd, int msg, IntPtr wp, out COMBOBOXINFO lp);
      [DllImport("user32.dll")]
      private static extern bool SetWindowPos(IntPtr hWnd, IntPtr after, int x, int y, int cx, int cy, int flags);
      [DllImport("user32.dll")]
      private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
    }
    

    VB.Net version:

    Imports System
    Imports System.Drawing
    Imports System.Windows.Forms
    Imports System.Runtime.InteropServices
    
    Public Class MyComboBox
        Inherits ComboBox
    
        'P/Invoke declarations
        Private Structure COMBOBOXINFO
            Public cbSize As Int32
            Public rcItem As RECT
            Public rcButton As RECT
            Public buttonState As Integer
            Public hwndCombo As IntPtr
            Public hwndEdit As IntPtr
            Public hwndList As IntPtr
        End Structure
    
        Private Structure RECT
            Public Left As Integer
            Public Top As Integer
            Public Right As Integer
            Public Bottom As Integer
        End Structure
    
    
        <DllImport("user32.dll", EntryPoint:="SendMessageW", CharSet:=CharSet.Unicode)>
        Private Shared Function SendMessageCb(hWnd As IntPtr, msg As Integer, wp As IntPtr, ByRef lp As COMBOBOXINFO) As IntPtr
        End Function
    
        <DllImport("user32.dll")>
        Private Shared Function SetWindowPos(hWnd As IntPtr, after As IntPtr, x As Integer, y As Integer, cx As Integer, cy As Integer, flags As Integer) As Boolean
        End Function
    
        <DllImport("user32.dll")>
        Private Shared Function GetWindowRect(hWnd As IntPtr, ByRef rc As RECT) As Boolean
        End Function
    
    
        Protected Overrides Sub OnDropDown(e As EventArgs)
              ' Is dropdown off the right side of the screen?
              Dim pos As Point = Me.PointToScreen(Me.Location)
              Dim scr As Screen = Screen.FromPoint(pos)
    
              If (scr.WorkingArea.Right < pos.X + Me.DropDownWidth) Then
                  Me.BeginInvoke(New Action(Sub()
    
                                                'Retrieve handle to dropdown list
                                                Dim info As COMBOBOXINFO = New COMBOBOXINFO()
                                                info.cbSize = Marshal.SizeOf(info)
                                                SendMessageCb(Me.Handle, &H164, IntPtr.Zero, info)
                                                'Move the dropdown window
                                                Dim rc As RECT
                                                GetWindowRect(info.hwndList, rc)
                                                Dim x As Integer = scr.WorkingArea.Right - (rc.Right - rc.Left)
                                                SetWindowPos(info.hwndList, IntPtr.Zero, x, rc.Top, 0, 0, 5)
                                            End Sub))
              End If
    
              MyBase.OnDropDown(e)
    
        End Sub
    
    
    
    End Class
    
    0 讨论(0)
提交回复
热议问题