From 52e99ff0fe944dfbdd0e42b8b9aad52bd801f180 Mon Sep 17 00:00:00 2001 From: DinahK-2SO <116714259+DinahK-2SO@users.noreply.github.com> Date: Wed, 3 Dec 2025 15:51:32 +0800 Subject: [PATCH 1/3] API Spec for SettingsIdentifier; FileTypeIndex; Title; FolderPicker.PickMultipleFoldersAsync --- specs/Storage.Pickers/FileOpenPicker.md | 31 ++++++++ specs/Storage.Pickers/FileSavePicker.md | 28 ++++++++ specs/Storage.Pickers/FolderPicker.md | 71 +++++++++++++++++++ .../Microsoft.Windows.Storage.Pickers.md | 19 +++++ 4 files changed, 149 insertions(+) diff --git a/specs/Storage.Pickers/FileOpenPicker.md b/specs/Storage.Pickers/FileOpenPicker.md index 525145381b..058e2af410 100644 --- a/specs/Storage.Pickers/FileOpenPicker.md +++ b/specs/Storage.Pickers/FileOpenPicker.md @@ -19,9 +19,12 @@ runtimeclass FileOpenPicker FileOpenPicker(Microsoft.UI.WindowId windowId); string CommitButtonText; + string Title; + string SettingsIdentifier; IMap> FileTypeChoices{ get; }; IVector FileTypeFilter{ get; }; + UInt32 FileTypeIndex; string SuggestedFolder; String SuggestedStartFolder; @@ -65,6 +68,14 @@ var openPicker = new FileOpenPicker(this.AppWindow.Id) // If not specified, the system uses a default label of "Open" (suitably translated). CommitButtonText = "Choose selected files", + // (Optional) specify the title of the picker. + // If not specified, the system uses a default title. + Title = "Open File", + + // (Optional) specify the settings identifier of the picker. + // It allows the picker to remember its state (e.g. size, location, etc) across sessions. + SettingsIdentifier = "MySettingsIdentifier", + // (Optional) group file types into labeled choices // FileTypeChoices takes precedence over FileTypeFilter when both defined. FileTypeChoices = { @@ -75,6 +86,12 @@ var openPicker = new FileOpenPicker(this.AppWindow.Id) // (Optional) specify file extension filters. If not specified, defaults to all files (*.*). FileTypeFilter = { ".txt", ".pdf", ".doc", ".docx" }, + // (Optional) specify the index of the file type filter to be selected by default. The index is 1-based. + // When it is 0 (the default value), the selected filter will be decided by API behavior. That is: + // When FileTypeFilter is in effect, auto-select the last one (All Files). + // Otherwise, auto-select the first one. + FileTypeIndex = 1, + // (Optional) specify the view mode of the picker dialog. If not specified, defaults to List. ViewMode = PickerViewMode.List, }; @@ -109,6 +126,14 @@ openPicker.SuggestedStartLocation(PickerLocationId::DocumentsLibrary); // If not specified, the system uses a default label of "Open" (suitably translated). openPicker.CommitButtonText(L"Choose selected files"); +// (Optional) specify the title of the picker. +// If not specified, the system uses a default title. +openPicker.Title(L"Open File"); + +// (Optional) specify the settings identifier of the picker. +// It allows the picker to remember its state (e.g. size, location, etc) across sessions. +openPicker.SettingsIdentifier(L"MySettingsIdentifier"); + // (Optional) group file types into labeled choices // FileTypeChoices takes precedence over FileTypeFilter when both defined. auto choices = openPicker.FileTypeChoices(); @@ -118,6 +143,12 @@ choices.Insert(L"Pictures", winrt::single_threaded_vector({ L".p // (Optional) specify file extension filters. If not specified, defaults to all files (*.*). openPicker.FileTypeFilter().ReplaceAll({ L".txt", L".pdf", L".doc", L".docx" }); +// (Optional) specify the index of the file type filter to be selected by default. The index is 1-based. +// When it is 0 (the default value), the selected filter will be decided by API behavior. That is: +// When FileTypeFilter is in effect, auto-select the last one (All Files). +// Otherwise, auto-select the first one. +openPicker.FileTypeIndex(1); + // (Optional) specify the view mode of the picker dialog. If not specified, defaults to List. openPicker.ViewMode(PickerViewMode::List); ``` diff --git a/specs/Storage.Pickers/FileSavePicker.md b/specs/Storage.Pickers/FileSavePicker.md index 4d28aeab5f..4d646ceb32 100644 --- a/specs/Storage.Pickers/FileSavePicker.md +++ b/specs/Storage.Pickers/FileSavePicker.md @@ -17,10 +17,14 @@ runtimeclass FileSavePicker FileSavePicker(Microsoft.UI.WindowId windowId); string CommitButtonText; + string Title; + string SettingsIdentifier; + string DefaultFileExtension; string SuggestedFileName; IMap> FileTypeChoices{ get; }; + UInt32 FileTypeIndex; string SuggestedFolder; String SuggestedStartFolder; @@ -64,12 +68,24 @@ var savePicker = new FileSavePicker(this.AppWindow.Id) // If not specified, the system uses a default label of "Save" (suitably translated). CommitButtonText = "Save Document", + // (Optional) specify the title of the picker. + // If not specified, the system uses a default title. + Title = "Save File", + + // (Optional) specify the settings identifier of the picker. + // It allows the picker to remember its state (e.g. size, location, etc) across sessions. + SettingsIdentifier = "MySettingsIdentifier", + // (Optional) categorized extension types. If not specified, "All Files (*.*)" is allowed. // Note that when "All Files (*.*)" is allowed, end users can save a file without an extension. FileTypeChoices = { { "Documents", new List { ".txt", ".doc", ".docx" } } }, + // (Optional) specify the index of the file type filter to be selected by default. + // The index is 1-based. + FileTypeIndex = 1, + // (Optional) specify the default file extension (will be appended to SuggestedFileName). // If not specified, no extension will be appended. DefaultFileExtension = ".txt", @@ -108,10 +124,22 @@ savePicker.SuggestedFileName(L"NewDocument"); // If not specified, the system uses a default label of "Save" (suitably translated). savePicker.CommitButtonText(L"Save Document"); +// (Optional) specify the title of the picker. +// If not specified, the system uses a default title. +savePicker.Title(L"Save File"); + +// (Optional) specify the settings identifier of the picker. +// It allows the picker to remember its state (e.g. size, location, etc) across sessions. +savePicker.SettingsIdentifier(L"MySettingsIdentifier"); + // (Optional) categorized extension types. If not specified, "All Files (*.*)" is allowed. // Note that when "All Files (*.*)" is allowed, end users can save a file without an extension. savePicker.FileTypeChoices().Insert(L"Text", winrt::single_threaded_vector({ L".txt" })); +// (Optional) specify the index of the file type filter to be selected by default. +// The index is 1-based. +savePicker.FileTypeIndex(1); + // (Optional) specify the default file extension (will be appended to SuggestedFileName). // If not specified, no extension will be appended. savePicker.DefaultFileExtension(L".txt"); diff --git a/specs/Storage.Pickers/FolderPicker.md b/specs/Storage.Pickers/FolderPicker.md index 6b0592cc76..5571b9068d 100644 --- a/specs/Storage.Pickers/FolderPicker.md +++ b/specs/Storage.Pickers/FolderPicker.md @@ -19,6 +19,8 @@ runtimeclass FolderPicker FolderPicker(Microsoft.UI.WindowId windowId); string CommitButtonText; + string Title; + string SettingsIdentifier; string SuggestedFolder; String SuggestedStartFolder; @@ -27,6 +29,7 @@ runtimeclass FolderPicker PickerViewMode ViewMode; Windows.Foundation.IAsyncOperation PickSingleFolderAsync(); + Windows.Foundation.IAsyncOperation> PickMultipleFoldersAsync(); } ``` @@ -66,6 +69,14 @@ var folderPicker = new FolderPicker(this.AppWindow.Id) // If not specified, the system uses a default label of "Open" (suitably translated). CommitButtonText = "Select Folder", + // (Optional) specify the title of the picker. + // If not specified, the system uses a default title. + Title = "Select Folder", + + // (Optional) specify the settings identifier of the picker. + // It allows the picker to remember its state (e.g. size, location, etc) across sessions. + SettingsIdentifier = "MySettingsIdentifier", + // (Optional) specify the view mode of the picker dialog. If not specified, default to List. ViewMode = PickerViewMode.List, }; @@ -100,6 +111,14 @@ folderPicker.SuggestedStartLocation(PickerLocationId::DocumentsLibrary); // If not specified, the system uses a default label of "Open" (suitably translated). folderPicker.CommitButtonText(L"Select Folder"); +// (Optional) specify the title of the picker. +// If not specified, the system uses a default title. +folderPicker.Title(L"Select Folder"); + +// (Optional) specify the settings identifier of the picker. +// It allows the picker to remember its state (e.g. size, location, etc) across sessions. +folderPicker.SettingsIdentifier(L"MySettingsIdentifier"); + // (Optional) specify the view mode of the picker dialog. If not specified, default to List. folderPicker.ViewMode(PickerViewMode::List); ``` @@ -148,6 +167,58 @@ else } ``` +## FolderPicker.PickMultipleFoldersAsync + +Displays a UI element that allows the user to choose multiple folders. + +Returns a collection of lightweight objects that have the path of the picked folders. + +Returns an empty list (`Count` = 0) if the folder dialog was cancelled or closed without a selection. + +### Examples + +C# + +```C# +using Microsoft.Windows.Storage.Pickers; + +var folderPicker = new FolderPicker(this.AppWindow.Id); + +var results = await folderPicker.PickMultipleFoldersAsync(); +if (results.Count > 0) +{ + var pickedFolderPaths = results.Select(f => f.Path); + foreach (var path in pickedFolderPaths) + { + // Do something with the folder path + } +} +else +{ + // error handling. +} +``` + +C++ +```C++ +#include +using namespace winrt::Microsoft::Windows::Storage::Pickers; + +FolderPicker folderPicker(AppWindow().Id()); +auto results{ co_await folderPicker.PickMultipleFoldersAsync() }; +if (results.Size() > 0) +{ + for (auto const& result : results) + { + auto path{ result.Path() }; + } +} +else +{ + // error handling. +} +``` + # See Also [PickFolderResult](./PickFolderResult.md) diff --git a/specs/Storage.Pickers/Microsoft.Windows.Storage.Pickers.md b/specs/Storage.Pickers/Microsoft.Windows.Storage.Pickers.md index 2036ab3ff6..17a0c1f0dc 100644 --- a/specs/Storage.Pickers/Microsoft.Windows.Storage.Pickers.md +++ b/specs/Storage.Pickers/Microsoft.Windows.Storage.Pickers.md @@ -57,6 +57,15 @@ to `SuggestedStartLocation`, then to the system default. catagorized filter types. When both `FileTypeChoices` and `FileTypeFilter` are provided, `FileTypeChoices` is used and `FileTypeFilter` is ignored. +1. Adding `FileTypeIndex` for `FileOpenPicker` and `FileSavePicker`. This allows setting the default selected file type filter index. Note this index is 1-based. When it is 0 (the default value), the selected filter might be override by the API's default behavior. + +1. The property `SettingsIdentifier` will be available in the new Storage.Pickers APIs from WindowsAppSDK2.0. `SettingsIdentifier` allows the picker to remember its state (e.g. size, location, etc) across sessions. When two different apps use the same string for SettingsIdentifier property, they will have their respective independent states. + +1. Adding `Title` for all 3 pickers. `Title` allows setting the title of the picker dialog. + +1. Adding `PickMultipleFoldersAsync` for `FolderPicker`. This allows selecting multiple folders in the folder picker dialog. + + # Conceptual pages # API @@ -119,9 +128,12 @@ namespace Microsoft.Windows.Storage.Pickers FileOpenPicker(Microsoft.UI.WindowId windowId); string CommitButtonText; + string Title; + string SettingsIdentifier; IMap> FileTypeChoices{ get; }; IVector FileTypeFilter{ get; }; + int FileTypeIndex; string SuggestedFolder; string SuggestedStartFolder; @@ -138,10 +150,14 @@ namespace Microsoft.Windows.Storage.Pickers FileSavePicker(Microsoft.UI.WindowId windowId); string CommitButtonText; + string Title; + string SettingsIdentifier; + string DefaultFileExtension; string SuggestedFileName; IMap> FileTypeChoices{ get; }; + int FileTypeIndex; string SuggestedFolder; string SuggestedStartFolder; @@ -155,6 +171,8 @@ namespace Microsoft.Windows.Storage.Pickers FolderPicker(Microsoft.UI.WindowId windowId); string CommitButtonText; + string Title; + string SettingsIdentifier; string SuggestedFolder; string SuggestedStartFolder; @@ -163,6 +181,7 @@ namespace Microsoft.Windows.Storage.Pickers PickerViewMode ViewMode; Windows.Foundation.IAsyncOperation PickSingleFolderAsync(); + Windows.Foundation.IAsyncOperation> PickMultipleFoldersAsync(); } } ``` From 7af6a89441af2a0583a03b3666a4eacd95c1f2d5 Mon Sep 17 00:00:00 2001 From: DinahK-2SO <116714259+DinahK-2SO@users.noreply.github.com> Date: Thu, 4 Dec 2025 15:50:08 +0800 Subject: [PATCH 2/3] adding FileSavePicker.ShowOverwritePrompt and FileSavePicker.CreateNewFileIfNotExists --- specs/Storage.Pickers/FileSavePicker.md | 19 +++++++++++++++++++ .../Microsoft.Windows.Storage.Pickers.md | 9 ++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/specs/Storage.Pickers/FileSavePicker.md b/specs/Storage.Pickers/FileSavePicker.md index 4d646ceb32..4cbaf66d51 100644 --- a/specs/Storage.Pickers/FileSavePicker.md +++ b/specs/Storage.Pickers/FileSavePicker.md @@ -26,6 +26,9 @@ runtimeclass FileSavePicker IMap> FileTypeChoices{ get; }; UInt32 FileTypeIndex; + Boolean ShowOverwritePrompt; + Boolean CreateNewFileIfNotExists; + string SuggestedFolder; String SuggestedStartFolder; PickerLocationId SuggestedStartLocation; @@ -86,6 +89,14 @@ var savePicker = new FileSavePicker(this.AppWindow.Id) // The index is 1-based. FileTypeIndex = 1, + // (Optional) Show a warning prompt of file overwrite when user tries to pick an existing file. + // set to true by default. + ShowOverwritePrompt = true, + + // (Optional) create an empty file when the picked file does not yet exist. + // set to true by default. + CreateNewFileIfNotExists = true, + // (Optional) specify the default file extension (will be appended to SuggestedFileName). // If not specified, no extension will be appended. DefaultFileExtension = ".txt", @@ -140,6 +151,14 @@ savePicker.FileTypeChoices().Insert(L"Text", winrt::single_threaded_vector> FileTypeChoices{ get; }; int FileTypeIndex; + bool ShowOverwritePrompt; + bool CreateNewFileIfNotExists; + string SuggestedFolder; string SuggestedStartFolder; PickerLocationId SuggestedStartLocation; From b5de7c20e2dd69caa8dcd85c4ff8b861f2fe3bc4 Mon Sep 17 00:00:00 2001 From: Dinah Xiaoman G <116714259+DinahK-2SO@users.noreply.github.com> Date: Thu, 4 Dec 2025 16:59:41 +0800 Subject: [PATCH 3/3] Add notes explaining the range of DefaultFileExtension --- specs/Storage.Pickers/FileSavePicker.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specs/Storage.Pickers/FileSavePicker.md b/specs/Storage.Pickers/FileSavePicker.md index 4cbaf66d51..14a9c94ad6 100644 --- a/specs/Storage.Pickers/FileSavePicker.md +++ b/specs/Storage.Pickers/FileSavePicker.md @@ -98,7 +98,8 @@ var savePicker = new FileSavePicker(this.AppWindow.Id) CreateNewFileIfNotExists = true, // (Optional) specify the default file extension (will be appended to SuggestedFileName). - // If not specified, no extension will be appended. + // Note: the default extension applies when the active filter is "All Files (*)" or includes multiple extensions, and the default extension is one of them. + // If not applied, no extension will be appended. DefaultFileExtension = ".txt", }; ``` @@ -160,7 +161,8 @@ savePicker.ShowOverwritePrompt(true); savePicker.CreateNewFileIfNotExists(true); // (Optional) specify the default file extension (will be appended to SuggestedFileName). -// If not specified, no extension will be appended. +// Note: the default extension applies when the selected filter is "All Files (*)" or includes multiple extensions, and the default extension is one of them. +// If not applied, no extension will be appended. savePicker.DefaultFileExtension(L".txt"); ```