|
| 1 | +--- |
| 2 | +title: Adding commands to your extension |
| 3 | +description: Learn how to add new commands to your Command Palette extension. |
| 4 | +ms.date: 3/23/2025 |
| 5 | +ms.topic: how-to |
| 6 | +no-loc: [PowerToys, Windows, Insider] |
| 7 | +# Customer intent: As a Windows developer, I want to learn how to develop an extension for the Command Palette. |
| 8 | +--- |
| 9 | + |
| 10 | +# Adding commands to your extension |
| 11 | + |
| 12 | +**Previous**: [Creating an extension](creating-an-extension.md). We'll be starting with the project created in that article. |
| 13 | + |
| 14 | +Now that you've created your extension, it's time to add some commands to it. |
| 15 | + |
| 16 | +## Add some commands |
| 17 | + |
| 18 | +We can start by navigating to the `ExtensionNamePage.cs` file. This file is the [ListPage](./microsoft-commandpalette-extensions-toolkit/listpage.md) that will be displayed when the user selects your extension. In there you should see: |
| 19 | + |
| 20 | +```csharp |
| 21 | +public ExtensionNamePage() |
| 22 | +{ |
| 23 | + Icon = IconHelpers.FromRelativePath("Assets\\StoreLogo.png"); |
| 24 | + Title = "My sample extension"; |
| 25 | + Name = "Open"; |
| 26 | +} |
| 27 | +public override IListItem[] GetItems() |
| 28 | +{ |
| 29 | + return [ |
| 30 | + new ListItem(new NoOpCommand()) { Title = "TODO: Implement your extension here" } |
| 31 | + ]; |
| 32 | +} |
| 33 | +``` |
| 34 | + |
| 35 | +Here you can see that we've set the icon for the page, the title, and the name that's shown at the top-level when you have the command selected. The **GetItems** method is where you'll return the list of commands that you want to show on this page. Right now, that's just returning a single command that does nothing. Let's instead try making that command open _this_ page in the user's default web browser. |
| 36 | + |
| 37 | +We can change the implementation of **GetItems** to the following: |
| 38 | + |
| 39 | +```csharp |
| 40 | +public override IListItem[] GetItems() |
| 41 | +{ |
| 42 | + var command = new OpenUrlCommand("https://learn.microsoft.com/windows/powertoys/command-palette/adding-commands"); |
| 43 | + return [ |
| 44 | + new ListItem(command) |
| 45 | + { |
| 46 | + Title = "Open the Command Palette documentation", |
| 47 | + } |
| 48 | + ]; |
| 49 | +} |
| 50 | +``` |
| 51 | + |
| 52 | +Re-deploy your app, run the "reload" command to refresh the extensions in the palette, and head to your extension. You should see that the command now opens the Command Palette documentation. |
| 53 | + |
| 54 | +The **OpenUrlCommand** is a helper for opening a URL in the user's default web browser. You can also implement an extension however you want. Let's instead make a new command, that shows a **MessageBox**. To do that, we need to create a new class that implements **IInvokableCommand**. |
| 55 | + |
| 56 | +```csharp |
| 57 | +using System.Runtime.InteropServices; |
| 58 | + |
| 59 | +namespace ExtensionName; |
| 60 | + |
| 61 | +internal sealed partial class ShowMessageCommand : InvokableCommand |
| 62 | +{ |
| 63 | + public override string Name => "Show message"; |
| 64 | + public override IconInfo Icon => new("\uE8A7"); |
| 65 | + |
| 66 | + public override CommandResult Invoke() |
| 67 | + { |
| 68 | + // 0x00001000 is MB_SYSTEMMODAL, which will display the message box on top of other windows. |
| 69 | + _ = MessageBox(0, "I came from the Command Palette", "What's up?", 0x00001000); |
| 70 | + return CommandResult.KeepOpen(); |
| 71 | + } |
| 72 | + |
| 73 | + |
| 74 | + [DllImport("user32.dll", CharSet = CharSet.Unicode)] |
| 75 | + public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type); |
| 76 | +} |
| 77 | +``` |
| 78 | + |
| 79 | +Now we can add this command to the list of commands in the `ExtensionNamePage.cs` file: |
| 80 | + |
| 81 | +```csharp |
| 82 | +public override IListItem[] GetItems() |
| 83 | +{ |
| 84 | + var command = new OpenUrlCommand("https://learn.microsoft.com/windows/powertoys/command-palette/creating-an-extension"); |
| 85 | + var showMessageCommand = new ShowMessageCommand(); |
| 86 | + return [ |
| 87 | + new ListItem(command) |
| 88 | + { |
| 89 | + Title = "Open the Command Palette documentation", |
| 90 | + }, |
| 91 | + new ListItem(showMessageCommand), |
| 92 | + ]; |
| 93 | +} |
| 94 | +``` |
| 95 | + |
| 96 | +Deploy and reload, and presto - a command to show a message box! |
| 97 | + |
| 98 | +> [!TIP] |
| 99 | +> At about this point, you'll probably want to initialize a git repo / {other source control method of your choice} for your project. This will make it easier to track changes, and to share your extension with others. |
| 100 | +> |
| 101 | +> We recommend using GitHub, as it's easy to collaborate on your extension with others, and get feedback, and share it with the world. |
| 102 | +
|
| 103 | +## Adding more pages |
| 104 | + |
| 105 | +So far, we've only worked with commands that "do something". However, you can also add commands that show additional pages withing the Command Palette. There are basically two types of "Commands" in the Palette: |
| 106 | +- **IInvokableCommand** - These are commands that *do something*. |
| 107 | +- **IPage** - These are commands that *show something*. |
| 108 | + |
| 109 | +Because **IPage** implementations are **ICommand**'s, you can use them anywhere you can use commands. This means you can add them to the top-level list of commands, or to a list of commands on a page, the context menu on an item, etc. |
| 110 | + |
| 111 | +There are two different kinds of pages you can show: |
| 112 | +- [ListPage](./microsoft-commandpalette-extensions-toolkit/listpage.md) - This is a page that shows a list of commands. This is what we've been working with so far. |
| 113 | +- [ContentPage](./microsoft-commandpalette-extensions-toolkit/contentpage.md) - This is a page that shows rich content to the user. This allows you to specify abstract content, and let Command Palette worry about rendering the content in a native experience. There are two different types of content supported so far: |
| 114 | + - [Markdown content](./using-markdown-content.md) - This is content that's written in Markdown, and is rendered in the Command Palette. See [MarkdownContent](./microsoft-commandpalette-extensions-toolkit/markdowncontent.md) for details. |
| 115 | + - [Form content](./using-form-pages.md) - This is content that shows a form to the user, and then returns the results of that form to the extension. These are powered by [Adaptive Cards](https://aka.ms/adaptive-cards) This is useful for getting user input, or displaying more complex layouts of information. See [FormContent](./microsoft-commandpalette-extensions-toolkit/formcontent.md) for details. |
| 116 | + |
| 117 | + |
| 118 | +Start by adding a new page that shows a list of commands. Create a new class that implements **ListPage**: |
| 119 | + |
| 120 | +```csharp |
| 121 | +using Microsoft.CommandPalette.Extensions.Toolkit; |
| 122 | +using System.Linq; |
| 123 | + |
| 124 | +namespace ExtensionName; |
| 125 | + |
| 126 | +internal sealed partial class MySecondPage : ListPage |
| 127 | +{ |
| 128 | + public MySecondPage() |
| 129 | + { |
| 130 | + Icon = new("\uF147"); // Dial2 |
| 131 | + Title = "My second page"; |
| 132 | + Name = "Open"; |
| 133 | + } |
| 134 | + |
| 135 | + public override IListItem[] GetItems() |
| 136 | + { |
| 137 | + // Return 100 CopyText commands |
| 138 | + return Enumerable |
| 139 | + .Range(0, 100) |
| 140 | + .Select(i => new ListItem(new CopyTextCommand($"{i}")) |
| 141 | + { |
| 142 | + Title = $"Copy text {i}" |
| 143 | + }).ToArray(); |
| 144 | + } |
| 145 | +} |
| 146 | +``` |
| 147 | + |
| 148 | +Next, update the `ExtensionNamePage.cs` to include this new page: |
| 149 | + |
| 150 | +```diff |
| 151 | + public override IListItem[] GetItems() |
| 152 | + { |
| 153 | + OpenUrlCommand command = new("https://learn.microsoft.com/windows/powertoys/command-palette/creating-an-extension"); |
| 154 | + return [ |
| 155 | + new ListItem(command) |
| 156 | + { |
| 157 | + Title = "Open the Command Palette documentation", |
| 158 | + }, |
| 159 | + new ListItem(new ShowMessageCommand()), |
| 160 | ++ new ListItem(new MySecondPage()) { Title = "My second page", Subtitle = "A second page of commands" }, |
| 161 | + ]; |
| 162 | + } |
| 163 | +``` |
| 164 | + |
| 165 | +Deploy, reload, and you should now see a new page in your extension that shows 100 commands that copy a number to the clipboard. |
| 166 | + |
| 167 | +### Next up: [Update a list of commands](update-a-list-of-commands.md) |
| 168 | + |
| 169 | +## Related content |
| 170 | + |
| 171 | +- [PowerToys Command Palette utility](overview.md) |
| 172 | +- [Extensibility overview](extensibility-overview.md) |
| 173 | +- [Extension samples](samples.md) |
0 commit comments