WidBar.SDK
1.0.8
dotnet add package WidBar.SDK --version 1.0.8
NuGet\Install-Package WidBar.SDK -Version 1.0.8
<PackageReference Include="WidBar.SDK" Version="1.0.8" />
<PackageVersion Include="WidBar.SDK" Version="1.0.8" />
<PackageReference Include="WidBar.SDK" />
paket add WidBar.SDK --version 1.0.8
#r "nuget: WidBar.SDK, 1.0.8"
#:package WidBar.SDK@1.0.8
#addin nuget:?package=WidBar.SDK&version=1.0.8
#tool nuget:?package=WidBar.SDK&version=1.0.8
Build a WidBar widget
WidBar.SDK is everything you need to build a widget for the WidBar taskbar.
A widget is a small packaged app that runs in its own process. WidBar launches
it, shows its taskbar preview, and hosts its flyout and settings windows over
IPC. You never touch the taskbar, windowing, processes or the rendering
transport: you write WinUI 3 content and logic, and the SDK does the rest.
This package is for widget developers. If you just want to use widgets, install WidBar from the Microsoft Store instead.
One plugin process serves every instance of your widget. If the user adds your
widget to two taskbars, CreatePlugin() is called twice in the same process, so
keep state in instance fields rather than statics.
A widget exposes up to three independent WinUI 3 surfaces:
| Surface | What it is | Method |
|---|---|---|
| Preview | Compact, transparent, rasterized content in a free taskbar space | CreatePreviewContent() |
| Flyout | A rich interactive popup opened when the user clicks the preview | CreateFlyoutContent() |
| Settings | Optional configuration UI, hosted by WidBar with Save/Cancel | CreateSettingsContent(...) |
1. Create a widget project
The quickest start is the widbar-widget template (host app plus MSIX packaging
project, wired up and building):
# install the template once (from the cloned template repo or a downloaded copy)
dotnet new install <path-to>\widbar-widget-template
dotnet new widbar-widget -n Contoso.Weather `
--PluginId com.contoso.weather --DisplayName "Contoso Weather"
Prefer to do it by hand? Create a packaged WinUI 3 app, add
<PackageReference Include="WidBar.SDK" Version="1.0.6" />, derive App from
WidgetHostApplication, and add the AppExtension to your package manifest (see
section 5). The template just saves you the boilerplate.
The full developer documentation lives in the template wiki.
2. What's in the project
MyWidget.ExtensionApp/ WinUI 3 executable that hosts your plugin
MyWidget (Package)/ MSIX packaging project, this is what you publish
The ExtensionApp depends only on WidBar.SDK. Add any other NuGet or native
dependency you like: it runs in your own process, so there are no version
conflicts with WidBar or with other widgets.
App bootstrap
App.xaml derives from the SDK application; App.xaml.cs returns your plugin:
<hosting:WidgetHostApplication
x:Class="MyWidget.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hosting="using:WidBar.SDK.Hosting">
<hosting:WidgetHostApplication.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</hosting:WidgetHostApplication.Resources>
</hosting:WidgetHostApplication>
public partial class App : WidgetHostApplication
{
public App() => InitializeComponent();
protected override IWidgetPlugin CreatePlugin() => new WeatherPlugin();
}
That is the entire process bootstrap. The SDK handles the host connection, preview rasterization, flyout/settings chrome, and lifecycle.
3. The plugin class
Implement IWidgetPlugin, or derive from WidgetPluginBase and override only
what you need:
public sealed class WeatherPlugin : WidgetPluginBase, IConfigurableWidgetPlugin
{
private WeatherSettings _settings = new();
private WeatherPreviewView? _preview;
public override string Id => "com.contoso.weather";
public override string Name => "Weather";
public override WidgetCategory Category => WidgetCategory.Information;
// Taskbar width (logical px); re-read after every settings change.
public override int PreviewLogicalWidth => _settings.Compact ? 120 : 188;
public override async Task InitializeAsync(IWidgetContext context)
{
_settings = WeatherSettings.FromJson(context.SettingsJson);
await base.InitializeAsync(context);
// timers, network, files under context.DataDirectory, and so on.
// call Context.RequestPreviewRefresh() whenever the preview should redraw.
}
// Preview: rasterizable XAML only (shapes, text, images; no swap chains).
public override UIElement? CreatePreviewContent() =>
_preview = WeatherPreviewView.Create(_settings);
// Flyout: any WinUI content, swap chains welcome.
public override UIElement? CreateFlyoutContent() => new WeatherFlyoutView(_settings);
// Settings: hosted by WidBar with Save/Cancel; call ctx.SaveSettings(json).
public UIElement? CreateSettingsContent(IWidgetSettingsContext ctx) =>
new WeatherSettingsView(ctx);
// Optional live preview while the user edits settings (and on cancel).
public override void OnSettingsDraftChanged(string json)
{
_settings = WeatherSettings.FromJson(json);
WeatherPreviewView.Apply(_preview, _settings);
}
}
Members at a glance
| Member | Purpose | WidgetPluginBase default |
|---|---|---|
Id |
Reverse-DNS identity, e.g. com.contoso.weather |
abstract |
Name / Description / Version |
Shown in WidBar | abstract / "" / "1.0.0" |
Category |
WidgetCategory enum |
Utility |
PreviewLogicalWidth |
Taskbar width in logical px; re-read after settings | 188 |
IsPreviewVisible |
Hide the preview without disposing the instance | true |
FlyoutWidth / FlyoutHeight |
Flyout size in logical px | 390 / 480 |
FlyoutBackdrop |
Transparent, Mica or Acrylic |
Transparent |
InitializeAsync(IWidgetContext) |
One-time async setup | stores Context |
CreatePreviewContent() |
Taskbar preview UI | null |
CreateFlyoutContent() |
Flyout UI (null means no flyout) |
null |
OnSettingsDraftChanged(json) |
Live settings preview | no-op |
DisposeAsync() |
Tear down timers/subscriptions | no-op |
IWidgetContext (passed to InitializeAsync): WidgetId, InstanceId,
SettingsJson, DataDirectory (created for you), and RequestPreviewRefresh().
IConfigurableWidgetPlugin adds a settings surface through
CreateSettingsContent(IWidgetSettingsContext). The context exposes
SettingsJson, SaveSettings(json) and RequestPreviewRefresh(). When you
implement it, the flyout automatically gets a gear button.
IWidgetFlyoutLifecycle (optional) gives you OnFlyoutShown() and
OnFlyoutHidden() so you can pause timers and subscriptions while the flyout is
hidden.
File drag and drop
When the user drags a file onto the preview, WidBar opens the flyout so the drag
can continue onto it. The preview itself never receives the file: the flyout is a
normal WinUI window, so you accept the drop there with standard Windows drag and
drop. Set AllowDrop="True" on your flyout root and handle DragOver and Drop:
root.AllowDrop = true;
root.DragOver += (_, e) => e.AcceptedOperation = DataPackageOperation.Copy;
root.Drop += async (_, e) =>
{
if (e.DataView.Contains(StandardDataFormats.StorageItems))
{
var items = await e.DataView.GetStorageItemsAsync();
// ... do something with the dropped files
}
};
This is how a "send file" style widget works: the user drops a file on the widget, the flyout opens, and the drop lands in your flyout UI.
4. The three surfaces
The preview is rasterizable XAML: shapes, text, images. Swap-chain content (Win2D
CanvasControl and friends) is not captured, so use it in the flyout instead.
The preview refreshes when you call RequestPreviewRefresh() (coalesced at about
20 fps), and WidBar handles hover and click for you.
The flyout is your own window content with SDK chrome. It takes full input and any framework feature, swap chains included.
Settings are your content in an SDK window with host-localized Save/Cancel, and
the draft hook gives you real-time preview while the user edits. Settings are
plugin-owned JSON: WidBar stores it per instance and hands it back on
InitializeAsync. You choose the schema.
5. Identity and packaging
You never hand-write plugin.json. Set these properties in the ExtensionApp
.csproj and the SDK build target generates obj\widbar\plugin.json for you:
<PropertyGroup>
<WidBarPluginId>com.contoso.weather</WidBarPluginId>
<WidBarPluginName>Weather</WidBarPluginName>
<WidBarPluginDescription>Compact weather widget.</WidBarPluginDescription>
<WidBarPluginCategory>Information</WidBarPluginCategory>
<WidBarPluginVersion>1.0.0</WidBarPluginVersion>
<WidBarPluginPreviewWidth>188</WidBarPluginPreviewWidth>
<WidBarPluginConfigurable>true</WidBarPluginConfigurable>
</PropertyGroup>
The packaging project declares the AppExtension that makes WidBar discover you,
and links the generated manifest into the Public folder:
<uap3:Extension Category="windows.appExtension">
<uap3:AppExtension Name="com.widbar.widget" Id="weather"
PublicFolder="Public" DisplayName="Weather">
<uap3:Properties>
<WidBarPluginId>com.contoso.weather</WidBarPluginId>
<WidBarSdkVersion>2</WidBarSdkVersion>
</uap3:Properties>
</uap3:AppExtension>
</uap3:Extension>
<Content Include="..\MyWidget.ExtensionApp\obj\widbar\plugin.json">
<Link>Public\plugin.json</Link>
</Content>
Also declare runFullTrust in capabilities. All your DLLs (managed and native)
are normal app payload of the executable.
6. Build, run and debug
- Build the packaging project (
Debug | x64) in Visual Studio, or withmsbuild "MyWidget (Package)\MyWidget (Package).wapproj" /p:Configuration=Debug /p:Platform=x64 /restore. - Deploy it so Windows registers the AppExtension: in Visual Studio use
Build > Deploy, or enable Developer Mode and register the generated loose
layout with
Add-AppxPackage -Register ...\AppxManifest.xml. - Start WidBar. Your widget appears in the catalog, so drag it onto the taskbar. WidBar watches the catalog, so there's no need to restart it.
7. Diagnostics
Anything your plugin writes with Debug.WriteLine or Trace.WriteLine, plus any
exception thrown from an SDK callback, is forwarded to WidBar's developer console
as [Plugin:<your-id>] entries (enable Developer mode in WidBar > Settings).
Startup and handshake problems are logged to
%LOCALAPPDATA%\Packages\<your-pfn>\LocalCache\Local\Temp\widbar-sdk.*.log.
If your process crashes it is restarted with backoff. After three consecutive failures the widget is disabled until the user re-enables it.
8. Publish
Build the packaging project for release and submit the .msixupload to the
Microsoft Store through Partner Center (your widget is a normal MSIX app). To
appear in WidBar's in-app showcase, open a PR adding your entry to the catalog at
andelby/winbar-showcase (id,
pluginId, name, summary, publisher, category, storeProductId, icon
URL, optional localized text).
9. Compatibility
WidBarSdkVersion in the manifest declares the host contract version (2). Set
a minimum host version if you rely on newer SDK behavior; older WidBar builds
will skip incompatible widgets rather than fail.
Source and samples: https://github.com/andelby/widbar-widget-template Full guide and API reference: https://github.com/andelby/widbar-widget-template/wiki
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-windows10.0.19041 is compatible. net9.0-windows was computed. net10.0-windows was computed. |
-
net8.0-windows10.0.19041
- Microsoft.WindowsAppSDK (>= 2.1.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.0.7: documentation refresh — the package README is now a developer-focused guide to building widgets; full developer wiki at github.com/andelby/widbar-widget-template/wiki. No API changes since 1.0.6.