From c4444e35d1c5bd4ccefd198c80e6cbff22e0df62 Mon Sep 17 00:00:00 2001 From: "Simon Zhao (BEYONDSOFT CONSULTING INC)" Date: Thu, 30 Jul 2026 17:31:34 +0800 Subject: [PATCH 1/2] Fix issue 14795: ComboBox with DropDownStyle.Simple renders incorrectly and displays an unexpected vertical scrollbar --- .../Controls/ComboBox/ComboBox.Modern.cs | 222 ++++++++++++++---- .../ComboBox/ComboBox.ModernComboAdapter.cs | 40 ++++ .../Forms/Controls/ComboBox/ComboBox.cs | 28 ++- .../System/Windows/Forms/ComboBoxTests.cs | 178 ++++++++++++++ 4 files changed, 414 insertions(+), 54 deletions(-) diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs index 90eeab9368b..f7458aa25ec 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs @@ -165,19 +165,6 @@ private ModernComboTargetState ComputeModernComboTargetState() { int topInset = chromeInsets.Top + Padding.Top; int bottomInset = chromeInsets.Bottom + Padding.Bottom; - editBounds.Y += topInset; - - editBounds.Height = Math.Max( - 1, - editBounds.Height - topInset - bottomInset); - - editBounds.Height = Math.Max( - 1, - Math.Min( - editBounds.Height, - ClientRectangle.Bottom - - bottomInset - - editBounds.Top)); // Inset the edit window horizontally so its rectangular corners clear the rounded // field arcs, and reserve the (now wider) drop-down button on the button side. @@ -189,30 +176,90 @@ private ModernComboTargetState ComputeModernComboTargetState() ModernControlVisualStyles.ComboBoxButtonExtraWidth, DeviceDpiInternal); - if (RightToLeft == RightToLeft.Yes) + if (DropDownStyle == ComboBoxStyle.Simple) { - // In RTL the drop-down button sits on the left, so its reservation goes there. - editBounds.X += rightInset + extraButtonWidth; + int dividerThickness = Math.Max( + 1, + ScaleHelper.ScaleToDpi( + ModernControlVisualStyles.BorderThickness, + DeviceDpiInternal)); + int simpleBottomShrink = ScaleHelper.ScaleToDpi(2, DeviceDpiInternal); + int simpleListBottom = ClientRectangle.Bottom - simpleBottomShrink - dividerThickness; + int simpleEditTop = topInset + ScaleHelper.ScaleToDpi(1, DeviceDpiInternal); + int selectionFieldHeight = Math.Max( + 1, + (int)PInvokeCore.SendMessage( + this, + PInvoke.CB_GETITEMHEIGHT, + (WPARAM)(-1))); + int minimumReadableHeight = Math.Max( + 1, + FontHeight + ScaleHelper.ScaleToDpi(2, DeviceDpiInternal)); + int preferredSimpleEditHeight = Math.Max(selectionFieldHeight, minimumReadableHeight) + + ScaleHelper.ScaleToDpi(1, DeviceDpiInternal); + int maxSimpleEditHeight = Math.Max( + 1, + simpleListBottom - dividerThickness - simpleEditTop); + + // Keep the editor in the top field lane with enough height for full glyph rendering, + // draw an accent divider below it, and let the permanent list consume the remaining + // space down to the rounded field border. + editBounds.Y = simpleEditTop; + editBounds.Height = Math.Min(preferredSimpleEditHeight, maxSimpleEditHeight); + editBounds.X = leftInset; + editBounds.Width = Math.Max( + 1, + ClientRectangle.Width - leftInset - rightInset); + + if (!simpleListBounds.IsEmpty) + { + simpleListBounds.X = editBounds.Left; + simpleListBounds.Width = editBounds.Width; + simpleListBounds.Y = editBounds.Bottom + dividerThickness; + simpleListBounds.Height = Math.Max( + 1, + simpleListBottom - simpleListBounds.Y); + } } else { - editBounds.X += leftInset; - } - - editBounds.Width = Math.Max( - 1, - editBounds.Width - leftInset - rightInset - extraButtonWidth); - - if (!simpleListBounds.IsEmpty) - { - int simpleListBottom = GetCurrentSimpleListBottom( - simpleListBounds.Bottom); + editBounds.Y += topInset; - simpleListBounds.Y = editBounds.Bottom + bottomInset; + editBounds.Height = Math.Max( + 1, + editBounds.Height - topInset - bottomInset); - simpleListBounds.Height = Math.Max( + editBounds.Height = Math.Max( + 1, + Math.Min( + editBounds.Height, + ClientRectangle.Bottom + - bottomInset + - editBounds.Top)); + + if (RightToLeft == RightToLeft.Yes) + { + // In RTL the drop-down button sits on the left, so its reservation goes there. + editBounds.X += rightInset + extraButtonWidth; + } + else + { + editBounds.X += leftInset; + } + + editBounds.Width = Math.Max( 1, - simpleListBottom - simpleListBounds.Y); + editBounds.Width - leftInset - rightInset - extraButtonWidth); + + if (!simpleListBounds.IsEmpty) + { + int simpleListBottom = GetCurrentSimpleListBottom( + simpleListBounds.Bottom); + simpleListBounds.Y = editBounds.Bottom + bottomInset; + simpleListBounds.Height = Math.Max( + 1, + simpleListBottom - simpleListBounds.Y); + } } } @@ -281,6 +328,60 @@ private void GetAdjustedNativeChildBounds( } } + private void ConfigureModernSimpleListSurface(HWND listHandle) + { + if (DropDownStyle != ComboBoxStyle.Simple + || !UsesModernComboAdapter + || listHandle.IsNull) + { + return; + } + + WINDOW_STYLE style = (WINDOW_STYLE)PInvokeCore.GetWindowLong( + listHandle, + WINDOW_LONG_PTR_INDEX.GWL_STYLE); + WINDOW_EX_STYLE exStyle = (WINDOW_EX_STYLE)PInvokeCore.GetWindowLong( + listHandle, + WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); + + WINDOW_STYLE updatedStyle = style & ~WINDOW_STYLE.WS_BORDER; + WINDOW_EX_STYLE updatedExStyle = exStyle & ~WINDOW_EX_STYLE.WS_EX_CLIENTEDGE; + + if (updatedStyle == style && updatedExStyle == exStyle) + { + return; + } + + if (updatedStyle != style) + { + PInvokeCore.SetWindowLong( + listHandle, + WINDOW_LONG_PTR_INDEX.GWL_STYLE, + (nint)updatedStyle); + } + + if (updatedExStyle != exStyle) + { + PInvokeCore.SetWindowLong( + listHandle, + WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, + (nint)updatedExStyle); + } + + PInvoke.SetWindowPos( + listHandle, + HWND.Null, + 0, + 0, + 0, + 0, + SET_WINDOW_POS_FLAGS.SWP_NOMOVE + | SET_WINDOW_POS_FLAGS.SWP_NOSIZE + | SET_WINDOW_POS_FLAGS.SWP_NOZORDER + | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE + | SET_WINDOW_POS_FLAGS.SWP_FRAMECHANGED); + } + private unsafe int GetCurrentSimpleListBottom( int fallback) { @@ -464,24 +565,63 @@ private void ApplyEditMargins( private void ApplyChildBounds(HWND childHandle, Rectangle targetBounds) { + bool isModernSimpleList = UsesModernComboAdapter + && DropDownStyle == ComboBoxStyle.Simple + && childHandle == _childListBox?.HWND; + if (childHandle.IsNull - || targetBounds.IsEmpty - || GetChildBounds(childHandle) == targetBounds) + || targetBounds.IsEmpty) { return; } - PInvoke.SetWindowPos( - childHandle, - HWND.Null, - targetBounds.Left, - targetBounds.Top, + if (GetChildBounds(childHandle) != targetBounds) + { + PInvoke.SetWindowPos( + childHandle, + HWND.Null, + targetBounds.Left, + targetBounds.Top, + targetBounds.Width, + targetBounds.Height, + SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE + | SET_WINDOW_POS_FLAGS.SWP_NOZORDER); + + _modernComboLayoutWriteCount++; + } + + if (isModernSimpleList) + { + ConfigureModernSimpleListClipRegion( + childHandle, + targetBounds); + } + } + + private void ConfigureModernSimpleListClipRegion( + HWND listHandle, + Rectangle targetBounds) + { + if (listHandle.IsNull) + { + return; + } + + int bottomShrink = ScaleHelper.ScaleToDpi(2, DeviceDpiInternal); + int visibleHeight = Math.Max(1, targetBounds.Height - bottomShrink); + using RegionScope region = new( + 0, + 0, targetBounds.Width, - targetBounds.Height, - SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE - | SET_WINDOW_POS_FLAGS.SWP_NOZORDER); + visibleHeight); - _modernComboLayoutWriteCount++; + if (PInvoke.SetWindowRgn( + listHandle, + region, + fRedraw: true) != 0) + { + region.RelinquishOwnership(); + } } private Rectangle GetChildBounds(HWND child) diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.ModernComboAdapter.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.ModernComboAdapter.cs index 1c0c272383a..393d77e90c0 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.ModernComboAdapter.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.ModernComboAdapter.cs @@ -92,6 +92,7 @@ public override void DrawFlatCombo( graphics, clientBounds); DrawDropDownButton(comboBox, graphics); + DrawSimpleEditListDivider(comboBox, graphics); switch (_flatStyle) { @@ -395,6 +396,45 @@ private static void CutOutRoundedCorners( parentColor); } + private static void DrawSimpleEditListDivider( + ComboBox comboBox, + Graphics graphics) + { + if (comboBox.DropDownStyle != ComboBoxStyle.Simple + || comboBox._childListBox is null) + { + return; + } + + Rectangle listBounds = comboBox.GetChildBounds(comboBox._childListBox.HWND); + if (listBounds.IsEmpty) + { + return; + } + + int dividerThickness = Math.Max( + 1, + ScaleHelper.ScaleToDpi( + ModernControlVisualStyles.BorderThickness, + comboBox.DeviceDpiInternal)); + int lineY = listBounds.Top - dividerThickness; + if (lineY < 0) + { + return; + } + + Padding chromeInsets = comboBox.GetModernChromeInsets(); + int left = chromeInsets.Left + comboBox.Padding.Left; + int right = comboBox.ClientRectangle.Right - chromeInsets.Right - comboBox.Padding.Right - 1; + if (right < left) + { + return; + } + + using var pen = Application.SystemVisualSettings.AccentColor.GetCachedPenScope(dividerThickness); + graphics.DrawLine(pen, left, lineY, right, lineY); + } + private static void DrawRoundedBorder( ComboBox comboBox, Graphics graphics, diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.cs index 0e2e5c6e0a7..25c3516d16c 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.cs @@ -355,7 +355,9 @@ protected override CreateParams CreateParams cp.Style |= (int)WINDOW_STYLE.WS_VSCROLL | PInvoke.CBS_HASSTRINGS | PInvoke.CBS_AUTOHSCROLL; cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_CLIENTEDGE; - if (!_integralHeight) + if (!_integralHeight + || (UsesModernComboAdapter + && DropDownStyle == ComboBoxStyle.Simple)) { cp.Style |= PInvoke.CBS_NOINTEGRALHEIGHT; } @@ -2408,6 +2410,12 @@ protected override unsafe void OnHandleCreated(EventArgs e) bool hasComboBoxInfo = PInvoke.GetComboBoxInfo( HWND, ref comboBoxInfo); + + if (hasComboBoxInfo) + { + ConfigureModernSimpleListSurface(comboBoxInfo.hwndList); + } + if (Application.IsDarkModeEnabled) { // Style the ComboBox Open-Button: @@ -3725,14 +3733,11 @@ protected override unsafe void WndProc(ref Message m) { switch (m.MsgInternal) { - // Modern VisualStyles: expand the client area to the full window so the drop-down - // button, which the themed ComboBox otherwise reserves as non-client (outside - // ClientRectangle), becomes part of the client and is covered by our rounded field. - // Simple combos have no drop-down button (their client already spans the full width - // and hosts a permanent list), so they must never be expanded. + // Modern VisualStyles: expand the client area to the full window so themed non-client + // reservations (for example the ComboBox-hosted scroll strip in Simple mode) are folded + // into client painting and can be normalized by modern layout. case PInvokeCore.WM_NCCALCSIZE: if (UsesModernComboAdapter - && DropDownStyle != ComboBoxStyle.Simple && m.WParamInternal != 0u) { RECT* ncRects = (RECT*)(nint)m.LParamInternal; @@ -3745,15 +3750,12 @@ protected override unsafe void WndProc(ref Message m) base.WndProc(ref m); break; - // Modern VisualStyles: comctl32 still reports the drop-down button region as a - // non-client hit (HTVSCROLL) even though WM_NCCALCSIZE folded it into our client - // area, so a button click would arrive as WM_NCLBUTTONDOWN and never reach the - // WM_LBUTTONDOWN hit-test below. Force HTCLIENT across the expanded client so the - // button click is delivered as a normal client message we can act on. + // Modern VisualStyles: after WM_NCCALCSIZE expands the client area, comctl32 can still + // report the folded strip as non-client (HTVSCROLL). Force HTCLIENT across the expanded + // client so interaction remains consistent with the modern layout. case PInvokeCore.WM_NCHITTEST: base.WndProc(ref m); if (UsesModernComboAdapter - && DropDownStyle != ComboBoxStyle.Simple && m.ResultInternal != PInvoke.HTCLIENT) { Point hitPoint = PointToClient(PARAM.ToPoint(m.LParamInternal)); diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs index 8ba593350fd..903b5fade7c 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs @@ -1213,6 +1213,136 @@ public void ComboBox_ModernChromeInsets_ScaleWithDpi( chromeInsets.Top); } + [WinFormsFact] + public void ComboBox_ModernSimple_EditFillsAvailableFieldWidth() + { + using SystemVisualSettingsTestScope settingsScope = new( + clientAreaAnimationEnabled: false, + highContrastEnabled: false); + using VisualStylesComboBox control = new() + { + DropDownStyle = ComboBoxStyle.Simple, + FlatStyle = FlatStyle.Standard, + Padding = Padding.Empty, + Size = new Size(180, 120), + VisualStylesMode = VisualStylesMode.Net11 + }; + control.CreateControl(); + + Rectangle editBounds = control.GetEditBounds(); + Padding chromeInsets = control.ModernChromeInsets; + int expectedLeft = chromeInsets.Left; + int expectedRight = control.ClientRectangle.Right - chromeInsets.Right; + + Assert.InRange(editBounds.Left, expectedLeft - 1, expectedLeft + 1); + Assert.InRange(editBounds.Right, expectedRight - 1, expectedRight + 1); + } + + [WinFormsFact] + public void ComboBox_ModernSimple_ListFillsAvailableFieldWidth() + { + using SystemVisualSettingsTestScope settingsScope = new( + clientAreaAnimationEnabled: false, + highContrastEnabled: false); + using VisualStylesComboBox control = new() + { + DropDownStyle = ComboBoxStyle.Simple, + FlatStyle = FlatStyle.Standard, + Padding = Padding.Empty, + Size = new Size(180, 120), + VisualStylesMode = VisualStylesMode.Net11 + }; + control.Items.AddRange(["one", "two", "three", "four", "five", "six", "seven", "eight"]); + control.CreateControl(); + + Rectangle listBounds = control.GetListBounds(); + Padding chromeInsets = control.ModernChromeInsets; + int expectedLeft = chromeInsets.Left; + int expectedRight = control.ClientRectangle.Right - chromeInsets.Right; + + Assert.True(listBounds.Left <= expectedLeft); + Assert.True(listBounds.Right >= expectedRight - 1); + } + + [WinFormsFact] + public void ComboBox_ModernSimple_EditAndList_DoNotOverlapAndFitFont() + { + using SystemVisualSettingsTestScope settingsScope = new( + clientAreaAnimationEnabled: false, + highContrastEnabled: false); + using Font font = new(Control.DefaultFont.FontFamily, 14f); + using VisualStylesComboBox control = new() + { + DropDownStyle = ComboBoxStyle.Simple, + FlatStyle = FlatStyle.Standard, + Font = font, + Padding = Padding.Empty, + Size = new Size(220, 140), + VisualStylesMode = VisualStylesMode.Net11 + }; + control.Items.AddRange(["one", "two", "three", "four", "five", "six", "seven", "eight"]); + control.CreateControl(); + + Rectangle editBounds = control.GetEditBounds(); + Rectangle listBounds = control.GetListBounds(); + + Assert.True(editBounds.Height >= control.FontHeight); + Assert.True(listBounds.Top > editBounds.Bottom); + } + + [WinFormsFact] + public void ComboBox_ModernSimple_ListIsBorderlessAndFillsRoundedField() + { + using SystemVisualSettingsTestScope settingsScope = new( + clientAreaAnimationEnabled: false, + highContrastEnabled: false); + using VisualStylesComboBox control = new() + { + DropDownStyle = ComboBoxStyle.Simple, + FlatStyle = FlatStyle.Standard, + Padding = Padding.Empty, + Size = new Size(220, 140), + VisualStylesMode = VisualStylesMode.Net11 + }; + control.Items.AddRange(["one", "two", "three", "four", "five", "six", "seven", "eight"]); + control.CreateControl(); + + Rectangle listBounds = control.GetListBounds(); + + Assert.False(control.ListHasBorderStyle()); + Assert.False(control.ListHasClientEdgeExStyle()); + Assert.True(listBounds.Left <= control.ModernChromeInsets.Left); + Assert.True(listBounds.Right >= control.ClientRectangle.Right - control.ModernChromeInsets.Right - 1); + } + + [WinFormsFact] + public void ComboBox_ModernSimple_DrawsAccentDividerBetweenEditAndList() + { + using SystemVisualSettingsTestScope settingsScope = new( + clientAreaAnimationEnabled: false, + highContrastEnabled: false); + using VisualStylesComboBox control = new() + { + DropDownStyle = ComboBoxStyle.Simple, + FlatStyle = FlatStyle.Standard, + Padding = Padding.Empty, + Size = new Size(220, 140), + VisualStylesMode = VisualStylesMode.Net11 + }; + control.Items.AddRange(["one", "two", "three", "four", "five", "six", "seven", "eight"]); + control.CreateControl(); + using Bitmap bitmap = new(control.Width, control.Height); + + control.DrawToBitmap(bitmap, new Rectangle(Point.Empty, control.Size)); + + Rectangle listBounds = control.GetListBounds(); + int dividerY = Math.Max(0, listBounds.Top - 1); + int sampleX = Math.Clamp(control.Width / 2, 0, control.Width - 1); + Color pixel = bitmap.GetPixel(sampleX, dividerY); + + Assert.True(ColorsAreClose(pixel, Application.SystemVisualSettings.AccentColor, channelTolerance: 3)); + } + [WinFormsFact] public void ComboBox_ModernSimple_RepeatedMetricChangeDoesNotAccumulatePadding() { @@ -1318,6 +1448,34 @@ public void ComboBox_CreateParams_GetDefault_ReturnsExpected() Assert.False(control.IsHandleCreated); } + [WinFormsFact] + public void ComboBox_CreateParams_Net11Simple_ContainsVScroll() + { + using SubComboBox control = new() + { + VisualStylesMode = VisualStylesMode.Net11, + DropDownStyle = ComboBoxStyle.Simple + }; + + CreateParams createParams = control.CreateParams; + + Assert.NotEqual(0, createParams.Style & (int)WINDOW_STYLE.WS_VSCROLL); + } + + [WinFormsFact] + public void ComboBox_CreateParams_Net11Simple_ContainsNoIntegralHeight() + { + using SubComboBox control = new() + { + VisualStylesMode = VisualStylesMode.Net11, + DropDownStyle = ComboBoxStyle.Simple + }; + + CreateParams createParams = control.CreateParams; + + Assert.NotEqual(0, createParams.Style & PInvoke.CBS_NOINTEGRALHEIGHT); + } + [WinFormsTheory] [InvalidEnumData] public void ComboBox_AutoCompleteMode_SetInvalidValue_ThrowsInvalidEnumArgumentException(AutoCompleteMode value) @@ -4046,6 +4204,26 @@ public Rectangle GetButtonBounds() comboBoxInfo.rcButton.Height); } + public bool ListHasBorderStyle() + { + COMBOBOXINFO comboBoxInfo = GetComboBoxInfo(); + WINDOW_STYLE listStyle = (WINDOW_STYLE)PInvokeCore.GetWindowLong( + comboBoxInfo.hwndList, + WINDOW_LONG_PTR_INDEX.GWL_STYLE); + + return (listStyle & WINDOW_STYLE.WS_BORDER) != 0; + } + + public bool ListHasClientEdgeExStyle() + { + COMBOBOXINFO comboBoxInfo = GetComboBoxInfo(); + WINDOW_EX_STYLE listExStyle = (WINDOW_EX_STYLE)PInvokeCore.GetWindowLong( + comboBoxInfo.hwndList, + WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE); + + return (listExStyle & WINDOW_EX_STYLE.WS_EX_CLIENTEDGE) != 0; + } + private unsafe COMBOBOXINFO GetComboBoxInfo() { COMBOBOXINFO comboBoxInfo = default; From 9a784e077214188ce9abe2977df4f1877ce7d98b Mon Sep 17 00:00:00 2001 From: "Simon Zhao (BEYONDSOFT CONSULTING INC)" Date: Fri, 31 Jul 2026 10:52:41 +0800 Subject: [PATCH 2/2] Handle feedback --- .../Controls/ComboBox/ComboBox.Modern.cs | 5 +- .../System/Windows/Forms/ComboBoxTests.cs | 61 ++++++++++++------- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs index f7458aa25ec..5cbf631d80e 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs @@ -183,7 +183,8 @@ private ModernComboTargetState ComputeModernComboTargetState() ScaleHelper.ScaleToDpi( ModernControlVisualStyles.BorderThickness, DeviceDpiInternal)); - int simpleBottomShrink = ScaleHelper.ScaleToDpi(2, DeviceDpiInternal); + const int bottomCropLogicalPixels = 2; + int simpleBottomShrink = ScaleHelper.ScaleToDpi(bottomCropLogicalPixels, DeviceDpiInternal); int simpleListBottom = ClientRectangle.Bottom - simpleBottomShrink - dividerThickness; int simpleEditTop = topInset + ScaleHelper.ScaleToDpi(1, DeviceDpiInternal); int selectionFieldHeight = Math.Max( @@ -196,7 +197,7 @@ private ModernComboTargetState ComputeModernComboTargetState() 1, FontHeight + ScaleHelper.ScaleToDpi(2, DeviceDpiInternal)); int preferredSimpleEditHeight = Math.Max(selectionFieldHeight, minimumReadableHeight) - + ScaleHelper.ScaleToDpi(1, DeviceDpiInternal); + + ScaleHelper.ScaleToDpi(2, DeviceDpiInternal); int maxSimpleEditHeight = Math.Max( 1, simpleListBottom - dividerThickness - simpleEditTop); diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs index 903b5fade7c..91f75ffb36f 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs @@ -625,17 +625,20 @@ public void ComboBox_ModernPadding_PositionsEditUsingTopAndBottom( Assert.True( bottomWeightedBounds.Top > topWeightedBounds.Top); - Assert.Equal( - topWeightedBounds.Height, - bottomWeightedBounds.Height); if (dropDownStyle == ComboBoxStyle.Simple) { + Assert.True(bottomWeightedBounds.Height >= control.FontHeight); Rectangle listBounds = control.GetListBounds(); - Assert.Equal( - bottomWeightedBounds.Bottom - + control.ModernChromeInsets.Bottom - + control.Padding.Bottom, - listBounds.Top); + Assert.True( + listBounds.Top + > bottomWeightedBounds.Bottom); + } + else + { + Assert.InRange( + bottomWeightedBounds.Height, + topWeightedBounds.Height - 2, + topWeightedBounds.Height + 2); } } @@ -842,11 +845,14 @@ public void ComboBox_ModernSimple_ResizeRefreshesListBounds() Assert.True( resizedListBounds.Bottom > initialListBounds.Bottom); - Assert.Equal( - control.GetEditBounds().Bottom - + control.ModernChromeInsets.Bottom - + control.Padding.Bottom, - resizedListBounds.Top); + Assert.True( + resizedListBounds.Top + > control.GetEditBounds().Bottom); + Assert.True( + resizedListBounds.Top + <= control.GetEditBounds().Bottom + + control.ModernChromeInsets.Bottom + + control.Padding.Bottom); } [WinFormsFact] @@ -1081,11 +1087,13 @@ public void ComboBox_ModernSimple_FontChangeRecomputesNativeSplit() Rectangle updatedEditBounds = control.GetEditBounds(); Assert.NotEqual(initialEditBounds.Height, updatedEditBounds.Height); - Assert.Equal( - updatedEditBounds.Bottom - + control.ModernChromeInsets.Bottom - + control.Padding.Bottom, - control.GetListBounds().Top); + int listTop = control.GetListBounds().Top; + Assert.True(listTop > updatedEditBounds.Bottom); + Assert.True( + listTop + <= updatedEditBounds.Bottom + + control.ModernChromeInsets.Bottom + + control.Padding.Bottom); int writeCount = control.ModernComboLayoutWriteCount; var state = GetNativeComboState(control); @@ -1336,11 +1344,22 @@ public void ComboBox_ModernSimple_DrawsAccentDividerBetweenEditAndList() control.DrawToBitmap(bitmap, new Rectangle(Point.Empty, control.Size)); Rectangle listBounds = control.GetListBounds(); - int dividerY = Math.Max(0, listBounds.Top - 1); int sampleX = Math.Clamp(control.Width / 2, 0, control.Width - 1); - Color pixel = bitmap.GetPixel(sampleX, dividerY); + int startY = Math.Max(0, listBounds.Top - 4); + int endY = Math.Max(0, listBounds.Top - 1); + bool foundDivider = false; + + for (int y = startY; y <= endY; y++) + { + Color pixel = bitmap.GetPixel(sampleX, y); + if (ColorsAreClose(pixel, Application.SystemVisualSettings.AccentColor, channelTolerance: 3)) + { + foundDivider = true; + break; + } + } - Assert.True(ColorsAreClose(pixel, Application.SystemVisualSettings.AccentColor, channelTolerance: 3)); + Assert.True(foundDivider); } [WinFormsFact]