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/4] 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/4] 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/4] 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"); ``` From 0e6bf29ce6b42075b3c7f8d0303a3f6f9e69df56 Mon Sep 17 00:00:00 2001 From: DinahK-2SO <116714259+DinahK-2SO@users.noreply.github.com> Date: Tue, 9 Dec 2025 17:19:41 +0800 Subject: [PATCH 4/4] resolve comments --- specs/Storage.Pickers/FileOpenPicker.md | 24 +++++----- specs/Storage.Pickers/FileSavePicker.md | 18 +++++--- .../Microsoft.Windows.Storage.Pickers.md | 46 +++++++++++++++---- 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/specs/Storage.Pickers/FileOpenPicker.md b/specs/Storage.Pickers/FileOpenPicker.md index 058e2af410..fe8b3230d1 100644 --- a/specs/Storage.Pickers/FileOpenPicker.md +++ b/specs/Storage.Pickers/FileOpenPicker.md @@ -24,7 +24,7 @@ runtimeclass FileOpenPicker IMap> FileTypeChoices{ get; }; IVector FileTypeFilter{ get; }; - UInt32 FileTypeIndex; + Int32 DefaultFileTypeFilterIndex; string SuggestedFolder; String SuggestedStartFolder; @@ -86,11 +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 index of the file type filter to be selected by default. + // The index is 0-based. + // When not specified, its value is -1 and the filter follows API's behavior. That is: + // When FileTypeFilter is in effect, auto-select the last one (All Files). + // Otherwise, auto-select the first one. + DefaultFileTypeFilterIndex = 1, // auto select Pictures // (Optional) specify the view mode of the picker dialog. If not specified, defaults to List. ViewMode = PickerViewMode.List, @@ -143,11 +144,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 index of the file type filter to be selected by default. +// The index is 0-based. +// When not specified, its value is -1 and the filter follows API's behavior. That is: +// When FileTypeFilter is in effect, auto-select the last one (All Files). +// Otherwise, auto-select the first one. +openPicker.DefaultFileTypeFilterIndex(1); // auto select Pictures // (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 4cbaf66d51..083f3e83ad 100644 --- a/specs/Storage.Pickers/FileSavePicker.md +++ b/specs/Storage.Pickers/FileSavePicker.md @@ -24,7 +24,7 @@ runtimeclass FileSavePicker string SuggestedFileName; IMap> FileTypeChoices{ get; }; - UInt32 FileTypeIndex; + Int32 DefaultFileTypeFilterIndex; Boolean ShowOverwritePrompt; Boolean CreateNewFileIfNotExists; @@ -82,12 +82,14 @@ var savePicker = new FileSavePicker(this.AppWindow.Id) // (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" } } + { "Text", new List {".txt"} }, + { "Documents", new List { ".doc", ".docx" } } }, // (Optional) specify the index of the file type filter to be selected by default. - // The index is 1-based. - FileTypeIndex = 1, + // The index is 0-based. + // When not specified, its value is -1. + DefaultFileTypeFilterIndex = 1, // this will auto-select Documents // (Optional) Show a warning prompt of file overwrite when user tries to pick an existing file. // set to true by default. @@ -145,11 +147,13 @@ 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" })); +savePicker.FileTypeChoices().Insert(L"Texts", winrt::single_threaded_vector({ L".txt" })); +savePicker.FileTypeChoices().Insert(L"Documents", winrt::single_threaded_vector({ L".doc", L".docx" })); // (Optional) specify the index of the file type filter to be selected by default. -// The index is 1-based. -savePicker.FileTypeIndex(1); +// The index is 0-based. +// When not specified, its value is -1. +savePicker.DefaultFileTypeFilterIndex(1); // this will auto-select Documents // (Optional) Show a warning prompt of file overwrite when user tries to pick an existing file. // set to true by default. diff --git a/specs/Storage.Pickers/Microsoft.Windows.Storage.Pickers.md b/specs/Storage.Pickers/Microsoft.Windows.Storage.Pickers.md index fd4743ed89..3d1b786dc6 100644 --- a/specs/Storage.Pickers/Microsoft.Windows.Storage.Pickers.md +++ b/specs/Storage.Pickers/Microsoft.Windows.Storage.Pickers.md @@ -57,17 +57,26 @@ 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. Adding `DefaultFileTypeFilterIndex` for `FileOpenPicker` and `FileSavePicker`. This allows +setting the default selected file type filter index. Note this index is 0-based. When it is +-1 (the default value), the selected filter might be override by the API's default behavior. -1. The property `SettingsIdentifier` for all 3 pickers 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. The property `SettingsIdentifier` for all 3 pickers 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 (Read more in Note 2). -1. Adding `ShowOverwritePrompt` for `FileSavePicker`. This Boolean properties default to `true` and control whether the picker warns about overwriting when user picked an existing file via FileSavePicker. +1. Adding `ShowOverwritePrompt` for `FileSavePicker`. This Boolean properties default to `true` and +control whether the picker warns about overwriting when user picked an existing file via +FileSavePicker. -1. Adding `CreateNewFileIfNotExists` for `FileSavePicker`. This Boolean properties default to `true` and control whether to auto-create the picked file when it doesn't exist. +1. Adding `CreateNewFileIfNotExists` for `FileSavePicker`. This Boolean properties default to `true` +and control whether to auto-create the picked file when it doesn't exist. 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. +1. Adding `PickMultipleFoldersAsync` for `FolderPicker`. This allows selecting multiple folders in +the folder picker dialog. # Conceptual pages @@ -137,7 +146,7 @@ namespace Microsoft.Windows.Storage.Pickers IMap> FileTypeChoices{ get; }; IVector FileTypeFilter{ get; }; - int FileTypeIndex; + int DefaultFileTypeFilterIndex; string SuggestedFolder; string SuggestedStartFolder; @@ -161,7 +170,7 @@ namespace Microsoft.Windows.Storage.Pickers string SuggestedFileName; IMap> FileTypeChoices{ get; }; - int FileTypeIndex; + int DefaultFileTypeFilterIndex; bool ShowOverwritePrompt; bool CreateNewFileIfNotExists; @@ -193,7 +202,9 @@ namespace Microsoft.Windows.Storage.Pickers } ``` -Note: **Understanding SuggestedStartFolder/SuggestedStartLocation vs SuggestedFolder:** +# Notes + +Note 1: **Understanding SuggestedStartFolder/SuggestedStartLocation vs SuggestedFolder:** These two kinds of properties have fundamentally different behaviors in terms of when and how they affect the picker: @@ -213,3 +224,22 @@ affect the picker: navigation history. `SuggestedStartFolder` takes precedence over `SuggestedStartLocation` when both specified. + +Note 2: **The implementation of SettingsIdentifier** + +When an app sets `SettingsIdentifier`, the picker persists its window placement and navigation +history through the underlying [`IFileDialog::SetClientGuid`](https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifiledialog-setclientguid) +API. The implementation derives that `ClientGuid` as follows: + +- First it tries to obtain the packaged app's Identity via [`GetCurrentApplicationUserModelId`](https://learn.microsoft.com/en-us/windows/win32/api/appmodel/nf-appmodel-getcurrentapplicationusermodelid). +- If the process has no package identity found (typical for unpackaged apps, win32 apps, etc.), + it falls back to the full path to the running executable retrieved from `wil::GetModuleFileNameW`. +- The chosen identifier is concatenated with the caller-provided `SettingsIdentifier` value using a + `"|"` format. That string is then hashed with MD5 + and coerced into an GUID. +- The calculated GUID will be passed to set the `ClientGuid`. + +This means the feature works for both packaged and unpackaged apps. Packaged apps remain distinct by +their package identity, while unpackaged apps are differentiated by the absolute path of their +executable. As long as an app uses a stable combination of package identity (or executable path) and +`SettingsIdentifier`, the picker will reopen with the same saved settings across sessions.