diff --git a/src/System.Windows.Forms.Design/src/PublicAPI.Unshipped.txt b/src/System.Windows.Forms.Design/src/PublicAPI.Unshipped.txt index e69de29bb2d..d5929c4099f 100644 --- a/src/System.Windows.Forms.Design/src/PublicAPI.Unshipped.txt +++ b/src/System.Windows.Forms.Design/src/PublicAPI.Unshipped.txt @@ -0,0 +1 @@ +virtual System.Windows.Forms.Design.FolderNameEditor.InitializeDialog(System.Windows.Forms.FolderBrowserDialog! folderBrowserDialog) -> void diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/FolderNameEditor.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/FolderNameEditor.cs index 49c1d937950..aff82a81648 100644 --- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/FolderNameEditor.cs +++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/FolderNameEditor.cs @@ -12,19 +12,19 @@ namespace System.Windows.Forms.Design; [CLSCompliant(false)] public partial class FolderNameEditor : UITypeEditor { - private FolderBrowser? _folderBrowser; - public override object? EditValue(ITypeDescriptorContext? context, IServiceProvider provider, object? value) { - if (_folderBrowser is null) - { - _folderBrowser = new FolderBrowser(); - InitializeDialog(_folderBrowser); - } + // The dialog is created locally and disposed at the end of the call so its + // native resources (Component/CommonDialog state) are released, and no stale + // configuration leaks between successive invocations of EditValue. + using FolderBrowserDialog folderBrowserDialog = new(); + InitializeDialog(folderBrowserDialog); - if (_folderBrowser.ShowDialog() == DialogResult.OK) + folderBrowserDialog.SelectedPath = value as string ?? string.Empty; + + if (folderBrowserDialog.ShowDialog() == DialogResult.OK) { - return _folderBrowser.DirectoryPath; + return folderBrowserDialog.SelectedPath; } return value; @@ -37,7 +37,17 @@ public partial class FolderNameEditor : UITypeEditor /// Initializes the folder browser dialog when it is created. This gives you an opportunity /// to configure the dialog as you please. The default implementation provides a generic folder browser. /// + [Obsolete] + [EditorBrowsable(EditorBrowsableState.Never)] protected virtual void InitializeDialog(FolderBrowser folderBrowser) { } + + /// + /// Initializes the folder browser dialog when it is created. This gives you an opportunity + /// to configure the dialog as you please. The default implementation provides a generic folder browser. + /// + protected virtual void InitializeDialog(FolderBrowserDialog folderBrowserDialog) + { + } } diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/InitialDirectoryEditor.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/InitialDirectoryEditor.cs index 00ab84f5c3c..03d9e74beec 100644 --- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/InitialDirectoryEditor.cs +++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/InitialDirectoryEditor.cs @@ -8,8 +8,8 @@ namespace System.Windows.Forms.Design; /// internal class InitialDirectoryEditor : FolderNameEditor { - protected override void InitializeDialog(FolderBrowser folderBrowser) + protected override void InitializeDialog(FolderBrowserDialog folderBrowserDialog) { - folderBrowser.Description = SR.InitialDirectoryEditorLabel; + folderBrowserDialog.Description = SR.InitialDirectoryEditorLabel; } } diff --git a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/SelectedPathEditor.cs b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/SelectedPathEditor.cs index 037d9f44c42..350805e75e6 100644 --- a/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/SelectedPathEditor.cs +++ b/src/System.Windows.Forms.Design/src/System/Windows/Forms/Design/SelectedPathEditor.cs @@ -8,8 +8,8 @@ namespace System.Windows.Forms.Design; /// internal class SelectedPathEditor : FolderNameEditor { - protected override void InitializeDialog(FolderBrowser folderBrowser) + protected override void InitializeDialog(FolderBrowserDialog folderBrowserDialog) { - folderBrowser.Description = SR.SelectedPathEditorLabel; + folderBrowserDialog.Description = SR.SelectedPathEditorLabel; } } diff --git a/src/System.Windows.Forms.Design/tests/UnitTests/System/Windows/Forms/Design/FolderNameEditorTests.cs b/src/System.Windows.Forms.Design/tests/UnitTests/System/Windows/Forms/Design/FolderNameEditorTests.cs index cfb9ee97af3..1b7bc3c60cb 100644 --- a/src/System.Windows.Forms.Design/tests/UnitTests/System/Windows/Forms/Design/FolderNameEditorTests.cs +++ b/src/System.Windows.Forms.Design/tests/UnitTests/System/Windows/Forms/Design/FolderNameEditorTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable disable @@ -38,71 +38,24 @@ public void FolderNameEditor_GetPaintValueSupported_Invoke_ReturnsFalse(ITypeDes public void FolderNameEditor_InitializeDialog_Invoke_Nop() { SubFolderNameEditor editor = new(); - editor.InitializeDialog(); - } - - public class FolderBrowserTests : FolderNameEditor - { - [Fact] - public void FolderBrowser_Ctor_Default() - { - FolderBrowser browser = new(); - Assert.Empty(browser.DirectoryPath); - Assert.Empty(browser.Description); - Assert.Equal(FolderBrowserStyles.RestrictToFilesystem, browser.Style); - Assert.Equal(FolderBrowserFolder.Desktop, browser.StartLocation); - } - - [Theory] - [NormalizedStringData] - public void FolderBrowser_Description_Set_GetReturnsExpected(string value, string expected) - { - FolderBrowser browser = new() - { - Description = value - }; - Assert.Equal(expected, browser.Description); - - // Set same. - browser.Description = value; - Assert.Equal(expected, browser.Description); - } - - [Theory] - [EnumData] - [InvalidEnumData] - protected void FolderBrowser_StartLocation_Set_GetReturnsExpected(FolderBrowserFolder value) - { - FolderBrowser browser = new() - { - StartLocation = value - }; - Assert.Equal(value, browser.StartLocation); + using FolderBrowserDialog dialog = new(); - // Set same. - browser.StartLocation = value; - Assert.Equal(value, browser.StartLocation); - } + // The base implementation is intentionally a no-op; invoking it should not + // throw and should leave the dialog's defaults untouched. + string originalSelectedPath = dialog.SelectedPath; + string originalDescription = dialog.Description; + Environment.SpecialFolder originalRootFolder = dialog.RootFolder; - [Theory] - [EnumData] - [InvalidEnumData] - protected void FolderBrowser_Style_Set_GetReturnsExpected(FolderBrowserStyles value) - { - FolderBrowser browser = new() - { - Style = value - }; - Assert.Equal(value, browser.Style); + editor.InitializeDialog(dialog); - // Set same. - browser.Style = value; - Assert.Equal(value, browser.Style); - } + Assert.Equal(originalSelectedPath, dialog.SelectedPath); + Assert.Equal(originalDescription, dialog.Description); + Assert.Equal(originalRootFolder, dialog.RootFolder); } private class SubFolderNameEditor : FolderNameEditor { - public void InitializeDialog() => base.InitializeDialog(null); + public new void InitializeDialog(FolderBrowserDialog folderBrowserDialog) => + base.InitializeDialog(folderBrowserDialog); } } diff --git a/src/test/integration/UIIntegrationTests/FolderNameEditorTests.cs b/src/test/integration/UIIntegrationTests/FolderNameEditorTests.cs index d39106f790f..4c2cf105256 100644 --- a/src/test/integration/UIIntegrationTests/FolderNameEditorTests.cs +++ b/src/test/integration/UIIntegrationTests/FolderNameEditorTests.cs @@ -30,21 +30,21 @@ public void FolderNameEditor_EditValue_ReturnsExpected() private class TestFolderNameEditor : FolderNameEditor { - private FolderBrowser? _folderBrowser; + private FolderBrowserDialog? _folderBrowserDialog; public override object? EditValue(ITypeDescriptorContext? context, IServiceProvider provider, object? value) { using DialogHostForm dialogOwnerForm = new(); - if (_folderBrowser is null) + if (_folderBrowserDialog is null) { - _folderBrowser = new FolderBrowser(); - InitializeDialog(_folderBrowser); + _folderBrowserDialog = new FolderBrowserDialog(); + InitializeDialog(_folderBrowserDialog); } - if (_folderBrowser.ShowDialog(dialogOwnerForm) == DialogResult.OK) + if (_folderBrowserDialog.ShowDialog(dialogOwnerForm) == DialogResult.OK) { - return _folderBrowser.DirectoryPath; + return _folderBrowserDialog.SelectedPath = value as string ?? string.Empty; } return value;