TipToe 0.1.4

There is a newer version of this package available.
See the version list below for details.
dotnet add package TipToe --version 0.1.4
                    
NuGet\Install-Package TipToe -Version 0.1.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="TipToe" Version="0.1.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="TipToe" Version="0.1.4" />
                    
Directory.Packages.props
<PackageReference Include="TipToe" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add TipToe --version 0.1.4
                    
#r "nuget: TipToe, 0.1.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package TipToe@0.1.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=TipToe&version=0.1.4
                    
Install as a Cake Addin
#tool nuget:?package=TipToe&version=0.1.4
                    
Install as a Cake Tool

TipToe

A quiet, careful and deliberate WinUI TeachingTip orchestrator.

Declare your teaching tips once. TipToe decides when — and whether — each one is worth showing.

using TipToe;

var guide = Guide.Attach(this, RootGrid);

guide.Add(new Tip
{
    Id       = "command-palette",
    Title    = "Jump anywhere",
    Subtitle = "Press Ctrl+K to search every command.",
    Target   = () => SearchBox,
    When     = () => DocumentCount >= 3,
});

…and, in the feature itself:

guide.Exercise("command-palette");

That is the whole contract. TipToe will not show that tip if the user has already opened the command palette, already dismissed it, is mid-drag, is looking at another app, saw a different tip four seconds ago, saw this tip earlier today, or the anchor is not currently on screen.

The principle throughout: a teaching tip at the wrong moment is worse than no teaching tip at all. Almost everything the library does is a reason not to show something.

Install

dotnet add package TipToe

net8.0-windows10.0.19041.0. Works in packaged and unpackaged apps. One AnyCPU assembly, no resource index, no per-architecture assets.

When a tip appears

A tip is shown only when every one of these is true, checked in this order:

Gate
1 Tips are enabled
2 The user has not exercised the feature
3 The user has not dismissed the tip
4 It is under its show budget (MaxShows, default 3)
5 Its prerequisites have been exercised
6 Its When condition is true
7 It has not been shown within RepeatDelay (default 1 day)
8 No other tip is showing
9 CooldownBetweenTips has elapsed (default 4 s)
10 The session cap is not reached (default: none)
11 StartupGrace has elapsed (default 4 s)
12 The window is active
13 No suppressor is active
14 The user has been idle for UserIdleFor (default 6 s)
15 The anchor resolves and is on screen

Inspect() reports which of these each tip is currently sitting on, computed through the same code path the runtime uses — so what it says and what happens cannot disagree.

Telling TipToe about your app

Suppressors — "not now", named so a blocked tip can explain itself:

guide.AddSuppressor("drag-in-progress", () => _dragging);
guide.AddSuppressor("playback",         () => Player.IsPlaying);

A tip can opt out of one with Ignores = ["playback"].

Activity from elsewhere — a single window is not the whole app:

secondWindow.PointerPressed += (_, _) => guide.ReportActivity();

Exercised — call from the feature, never from near the tip, so a user who discovered it on their own is never taught it afterwards. Safe to call every time; only the first has any effect.

Options

Every value has a defensible default; nothing is required.

var guide = Guide.Attach(window, host, new TipToeOptions
{
    UserIdleFor         = TimeSpan.FromSeconds(6),
    StartupGrace        = TimeSpan.FromSeconds(4),
    CooldownBetweenTips = TimeSpan.FromSeconds(4),
    RepeatDelay         = TimeSpan.FromDays(1),
    MaxTipsPerSession   = 0,            // unlimited
    DefaultMaxShows     = 3,
    StateRevision       = 1,            // bump to discard everything persisted
    Log                 = m => Debug.WriteLine(m),
    Presenter           = new TeachingTipPresenter { StyleTip = t => t.Background = MyBrush },
});

Validate() runs at attach and throws on a configuration that could never work — a guide that runs perfectly and shows nothing is a bad way to find that out.

Bring your own control

TipToe owns whether and when; it does not own what it looks like. Implement ITipPresenter to use a custom coach-mark, callout or inline banner, globally or for a single tip:

public sealed class MyCoachMark : ITipPresenter
{
    public void Initialize(Panel host) { ... }
    public bool IsShowing => ...;
    public void Show(TipPresentation p) { ... }
    public void Hide() { ... }
    public event EventHandler<TipClosedEventArgs>? Closed;
}

TeachingTipPresenter is the default and carries all the WinUI-specific handling, so an app that wants none of it pays nothing for it.

Storage

Defaults to app-local settings when the app has package identity, and a JSON file under %LOCALAPPDATA% when it does not. Supply your own ITipStore to put tip state anywhere else — it is a three-member string-to-string interface.

Debugging

foreach (var d in guide.Inspect())
    Debug.WriteLine(d);   // command-palette: UserNotIdle (3.4s left) [shown 1]

or drop in the panel:

DebugPane.Content = new TipsInspector { Guide = guide };

It lists every tip, why each is or is not showing, and offers per-tip and global resets. It only polls while it is on screen.

Why it behaves the way it does

See docs/design-notes.md — presence vs engagement vs idleness, refunding tips that never rendered, why GetLastInputInfo and CompositionTarget.Rendering were both rejected, and why the package contains no XAML.

License

MIT © Arcadio Garcia

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 92 8/15/2026
0.1.5 101 8/7/2026
0.1.4 93 8/5/2026