Edit

File and folder pickers

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 null return — it means the user cancelled the dialog.
  • Use DialogFilter to 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