diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/MaskedTextBoxTextEditorDropDown.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/MaskedTextBoxTextEditorDropDown.cs index 54ac9049bb7..538014edd98 100644 --- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/MaskedTextBoxTextEditorDropDown.cs +++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/MaskedTextBoxTextEditorDropDown.cs @@ -5,6 +5,11 @@ namespace System.Windows.Forms.Design; internal class MaskedTextBoxTextEditorDropDown : UserControl { + // Logical (96 DPI) constants. The actual device-pixel values are recomputed in + // RescaleConstantsForDpi so that PerMonitorV2 DPI changes are honoured. + private const int LogicalPadding = 16; + private static readonly Drawing.Size s_logicalSize = new(100, 52); + private bool _cancel; private readonly MaskedTextBox _cloneMtb; private readonly ErrorProvider _errorProvider; @@ -48,8 +53,11 @@ public MaskedTextBoxTextEditorDropDown(MaskedTextBox maskedTextBox) BackColor = Drawing.SystemColors.Control; BorderStyle = BorderStyle.FixedSingle; Name = "MaskedTextBoxTextEditorDropDown"; - Padding = new Padding(16); - Size = new Drawing.Size(100, 52); + + // Apply the initial DPI-scaled padding/size. Subsequent DPI changes are + // picked up automatically through RescaleConstantsForDpi. + RescaleConstantsForDpi(DeviceDpi, DeviceDpi); + ((System.ComponentModel.ISupportInitialize)(_errorProvider)).EndInit(); ResumeLayout(false); PerformLayout(); @@ -80,6 +88,16 @@ protected override bool ProcessDialogKey(Keys keyData) return base.ProcessDialogKey(keyData); } + protected override void RescaleConstantsForDpi(int deviceDpiOld, int deviceDpiNew) + { + base.RescaleConstantsForDpi(deviceDpiOld, deviceDpiNew); + + // DeviceDpi has already been updated to deviceDpiNew by the framework before + // this call, so LogicalToDeviceUnits returns values scaled to the new DPI. + Padding = new Padding(LogicalToDeviceUnits(LogicalPadding)); + Size = LogicalToDeviceUnits(s_logicalSize); + } + private void maskedTextBox_MaskInputRejected(object? sender, MaskInputRejectedEventArgs e) { _errorProvider.SetError(_cloneMtb, MaskedTextBoxDesigner.GetMaskInputRejectedErrorMessage(e)); diff --git a/src/System.Windows.Forms.Design/tests/UnitTests/System/Windows/Forms/Design/MaskedTextBoxTextEditorDropDownTests.cs b/src/System.Windows.Forms.Design/tests/UnitTests/System/Windows/Forms/Design/MaskedTextBoxTextEditorDropDownTests.cs index 617e9a797ba..92322d30e2f 100644 --- a/src/System.Windows.Forms.Design/tests/UnitTests/System/Windows/Forms/Design/MaskedTextBoxTextEditorDropDownTests.cs +++ b/src/System.Windows.Forms.Design/tests/UnitTests/System/Windows/Forms/Design/MaskedTextBoxTextEditorDropDownTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Drawing; + namespace System.Windows.Forms.Design.Tests; public class MaskedTextBoxTextEditorDropDownTests @@ -54,4 +56,17 @@ public void MaskInputRejected_SetsError_WhenInputRejected() dropDownMaskedTextBox.Text = "invalid"; errorProvider.GetError(dropDownMaskedTextBox).Should().Contain(SR.MaskedTextBoxHintDigitExpected); } + + [Fact] + public void DropDown_SizeAndPadding_ScalesWithDPI() + { + using MaskedTextBox maskedTextBox = new(); + using MaskedTextBoxTextEditorDropDown dropDown = new(maskedTextBox); + + // Simulate a DPI change and verify that the dropdown recomputes its logical constants. + dropDown.TestAccessor.Dynamic.RescaleConstantsForDpi(96, 192); + + dropDown.Size.Should().Be(new Size(100, 52)); + dropDown.Padding.Should().Be(new Padding(16)); + } }