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;
Comment thread
JayashreeSF3546 marked this conversation as resolved.
case PInvokeCore.WM_MOUSEMOVE:
if (_childWindowType == ChildWindowType.DropDownList)
{
Expand Down Expand Up @@ -153,5 +165,26 @@ 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 calculatedHeight = _owner.GetCalculatedDropDownHeight();

// Only shrink stale native height. Never grow over USER32's proposed height,
// because USER32 may have clamped it to fit the monitor work area.
if (calculatedHeight > 0 && pos->cy > calculatedHeight)
{
pos->cy = calculatedHeight;
}
Comment thread
JayashreeSF3546 marked this conversation as resolved.
}
}
}
}
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 @@ -22,4 +22,72 @@ public void ComboBoxChildNativeWindow_GetChildAccessibleObject()
Assert.True(childNativeWindow.TestAccessor.Dynamic.GetChildAccessibleObject() is ComboBox.ChildAccessibleObject);
}
}

[WinFormsFact]
public void ComboBox_DropDownHeight_UpdatesAfterItemsClear()
{
using ComboBox comboBox = new() { DropDownStyle = ComboBoxStyle.DropDown, ItemHeight = 20 };
comboBox.Items.Add("Item 1");
comboBox.Items.Add("Item 2");
comboBox.Items.Add("Item 3");
comboBox.CreateControl();
comboBox.DroppedDown = true;

var childNativeWindow = comboBox.GetListNativeWindow();
Assert.NotNull(childNativeWindow);
PInvokeCore.GetWindowRect(childNativeWindow.HWND, out RECT rect);
int heightBeforeClear = rect.Height;
comboBox.DroppedDown = false;

comboBox.Items.Clear();
comboBox.DroppedDown = true;
PInvokeCore.GetWindowRect(childNativeWindow.HWND, out RECT rect1);
int heightAfterClear = rect1.Height;
comboBox.DroppedDown = false;

bool heightReduced = heightBeforeClear > heightAfterClear;
Assert.True(heightReduced);
Assert.NotEqual(heightBeforeClear, heightAfterClear);

comboBox.Items.Add("Item 1");
comboBox.Items.Add("Item 2");
comboBox.DroppedDown = true;
PInvokeCore.GetWindowRect(childNativeWindow.HWND, out RECT rect2);
int heightAfterAdd = rect2.Height;

bool heightIncreased = heightAfterAdd > heightAfterClear;
Assert.True(heightIncreased);
Assert.NotEqual(heightAfterAdd, heightAfterClear);
}

[WinFormsFact]
public void ComboBox_DropDownHeight_UpdatesAfterRemovingAllItems()
{
using ComboBox comboBox = new() { DropDownStyle = ComboBoxStyle.DropDown, ItemHeight = 20 };
comboBox.Items.Add("Item 1");
comboBox.Items.Add("Item 2");
comboBox.Items.Add("Item 3");
comboBox.CreateControl();
comboBox.DroppedDown = true;

var childNativeWindow = comboBox.GetListNativeWindow();
Assert.NotNull(childNativeWindow);
PInvokeCore.GetWindowRect(childNativeWindow.HWND, out RECT rect);
int heightBeforeClear = rect.Height;
comboBox.DroppedDown = false;

for (int i = 0; i < 3; i++)
{
comboBox.Items.RemoveAt(0);
}

comboBox.DroppedDown = true;
PInvokeCore.GetWindowRect(childNativeWindow.HWND, out RECT rect1);
int heightAfterClear = rect1.Height;
comboBox.DroppedDown = false;

bool heightReduced = heightBeforeClear > heightAfterClear;
Assert.True(heightReduced);
Assert.NotEqual(heightBeforeClear, heightAfterClear);
}
}
Loading