Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Show native OS file and folder picker dialogs using the ShellExtensibility helpers.
Note
This guide uses the VisualStudio.Extensibility SDK. See Choose the right extensibility model for model comparison.
Full example
The complete implementation:
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace FilePickerSample;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Commands;
using Microsoft.VisualStudio.Extensibility.Shell.FileDialog;
[VisualStudioContribution]
public class OpenFileCommand(VisualStudioExtensibility extensibility) : Command(extensibility)
{
public override CommandConfiguration CommandConfiguration => new("%FilePickerSample.OpenFileCommand.DisplayName%")
{
TooltipText = "%FilePickerSample.OpenFileCommand.TooltipText%",
Placements = [CommandPlacement.KnownPlacements.ToolsMenu],
Icon = new(ImageMoniker.KnownValues.OpenFileDialog, IconSettings.IconAndText),
};
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken ct)
{
FileDialogOptions options = new()
{
InitialFileName = "test.cs",
Filters = new DialogFilters([
new("Log Files", "*.txt", "*.log"),
new("CSharp Files", "*.cs"),
])
{
DefaultFilterIndex = 1,
},
};
string? filePath = await this.Extensibility.Shell().ShowOpenFileDialogAsync(options, ct);
Debug.WriteLine($"Selected file path: {filePath ?? "No selection"}");
}
}
Tip
See the full working sample: FilePickerSample ↗
Related concepts: Remote UI — the data-binding model used for Visual Studio UI
Understand the example
Open a file
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
FileDialogOptions options = new()
{
Title = "Select a file",
Filters = new DialogFilters(
new DialogFilter("Text Files", ".txt", ".md"),
new DialogFilter("All Files", ".*"))
};
string? filePath = await this.Extensibility.Shell().ShowOpenFileDialogAsync(options, cancellationToken);
}
Open multiple files
FileDialogOptions options = new();
IReadOnlyList<string>? filePaths = await this.Extensibility.Shell()
.ShowOpenMultipleFilesDialogAsync(options, cancellationToken);
Save a file
FileDialogOptions options = new()
{
Title = "Save As",
InitialFileName = "document.txt"
};
string? filePath = await this.Extensibility.Shell().ShowSaveAsFileDialogAsync(options, cancellationToken);
Open a folder
FolderDialogOptions options = new()
{
Title = "Choose a folder",
InitialDirectory = @"C:\Projects"
};
string? folderPath = await this.Extensibility.Shell().ShowOpenFolderDialogAsync(options, cancellationToken);
Options reference
FileDialogOptions
| Property | Type | Description |
|---|---|---|
Title |
string |
Dialog title. Defaults to Open or Save As. |
InitialFileName |
string |
Pre-filled filename in the dialog input box. |
Filters |
DialogFilters |
File type filters (for example, *.txt, *.cs). |
FolderDialogOptions
| Property | Type | Description |
|---|---|---|
Title |
string |
Dialog title. |
InitialDirectory |
string |
Absolute path to start in. Defaults to the last opened directory. |
Tips
✅ DO
- Check for
nullreturn — it means the user cancelled the dialog. - Use
DialogFilterto restrict visible file types to what your extension needs.
❌ DON'T
- Use hardcoded paths for
InitialDirectory— prefer environment-based or user-relative paths. - Use file pickers when you already know the file path — they're for user selection only.
🔧 Troubleshooting
| Symptom | Fix |
|---|---|
ShowOpenFileDialogAsync throws |
Verify FileDialogOptions is not null and the InitialFileName (if set) exists on disk. |
Next steps
- Dialogs — custom dialogs with Remote UI content
- User prompts — simple message boxes