Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ protected override unsafe void WndProc(ref Message m)
case PInvokeCore.WM_GETOBJECT:
WmGetObject(ref m);
return;
case PInvokeCore.WM_WINDOWPOSCHANGING:
if (_childWindowType == ChildWindowType.DropDownList)
{
WmWindowPosChanging(ref m);
DefWndProc(ref m);
}
else
{
_owner.ChildWndProc(ref m);
}

break;
case PInvokeCore.WM_MOUSEMOVE:
if (_childWindowType == ChildWindowType.DropDownList)
{
Expand Down Expand Up @@ -153,5 +165,23 @@ private unsafe void WmGetObject(ref Message m)
throw new InvalidOperationException(SR.RichControlLresult, e);
}
}

private unsafe void WmWindowPosChanging(ref Message m)
{
// The native ComboBox sizes the dropdown list during its own layout
// pass (after CBN_DROPDOWN fires). Intercept here to enforce the
// managed computed height before the OS commits the final size.
// This ensures the UI reflects Items.Count (or explicit DropDownHeight)
// even when the list is empty or items are cleared at runtime.
WINDOWPOS* pos = (WINDOWPOS*)(nint)m.LParamInternal;
if (pos is not null && (pos->flags & SET_WINDOW_POS_FLAGS.SWP_NOSIZE) == 0)
{
int height = _owner.GetCalculatedDropDownHeight();
if (pos->cy != height)
{
pos->cy = height;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3327,14 +3327,8 @@ public override string ToString()
return $"{s}, Items.Count: {_itemsCollection?.Count ?? 0}";
}

private void UpdateDropDownHeight()
private int GetCalculatedDropDownHeight()
{
if (_dropDownHandle.IsNull)
{
return;
}

// Now use the DropDownHeight property instead of calculating the Height...
int height = DropDownHeight;
if (height == DefaultDropDownHeight)
{
Expand All @@ -3343,6 +3337,19 @@ private void UpdateDropDownHeight()
height = ItemHeight * count + 2;
}

return height;
}

private void UpdateDropDownHeight()
{
if (_dropDownHandle.IsNull)
{
return;
}

// Now use the DropDownHeight property instead of calculating the Height...
int height = GetCalculatedDropDownHeight();

PInvoke.SetWindowPos(
_dropDownHandle,
HWND.HWND_TOP,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2742,6 +2742,60 @@ public void ComboBox_CorrectHeightAfterSetDropDownStyleSimple()
handleCreatedInvoked.Should().Be(2);
}

[WinFormsFact]
public void ComboBox_GetCalculatedDropDownHeight_Reflects_Items_Clear()
{
using ComboBox combo = new();
combo.DropDownStyle = ComboBoxStyle.DropDown;

// Add items to influence calculated height and create handle.
for (int i = 0; i < 20; i++)
{
combo.Items.Add($"item{i}");
}

Assert.NotEqual(IntPtr.Zero, combo.Handle);

MethodInfo mi = typeof(ComboBox).GetMethod("GetCalculatedDropDownHeight", BindingFlags.Instance | BindingFlags.NonPublic);
Assert.NotNull(mi);

int heightWithItems = (int)mi.Invoke(combo, null);

combo.Items.Clear();

mi = typeof(ComboBox).GetMethod("GetCalculatedDropDownHeight", BindingFlags.Instance | BindingFlags.NonPublic);
Assert.NotNull(mi);
int heightAfterClear = (int)mi.Invoke(combo, null);

// After clearing items the calculated height should change and not remain the previous items height.
Assert.NotEqual(heightWithItems, heightAfterClear);
}

[WinFormsFact]
public void ComboBox_GetCalculatedDropDownHeight_Uses_DropDownHeight_When_NoItems()
{
using ComboBox combo = new();
combo.DropDownStyle = ComboBoxStyle.DropDown;

// Add items to influence calculated height and create handle.
for (int i = 0; i < 2; i++)
{
combo.Items.Add($"item{i}");
}

// Ensure handle exists and items are empty.
Assert.NotEqual(IntPtr.Zero, combo.Handle);
combo.Items.Clear();

MethodInfo mi = typeof(ComboBox).GetMethod("GetCalculatedDropDownHeight", BindingFlags.Instance | BindingFlags.NonPublic);
Assert.NotNull(mi);

int calculated = (int)mi.Invoke(combo, null);

// Calculated height should not exceed the explicit DropDownHeight when there are no items.
Assert.InRange(calculated, 0, combo.DropDownHeight);
}

private void InitializeItems(ComboBox comboBox, int numItems)
{
for (int i = 0; i < numItems; i++)
Expand Down
Loading