feat(tray): Add balloon tip support to NotifyIcon#1715
Conversation
Introduce balloon tip functionality for the tray NotifyIcon. Adds a ToolTipIcon enum and new dependency properties (BalloonTipTitle, BalloonTipText, BalloonTipIcon), routed events (BalloonTipClick, BalloonTipShown, BalloonTipClose) and ShowBalloonTip overloads on NotifyIcon. InternalNotifyIconManager now stores balloon properties, exposes ShowBalloonTip which builds NOTIFYICONDATA (with length limits) and maps icon types to dwInfoFlags, and raises corresponding events. Also wires up native WM message constants in User32 and updates INotifyIcon to include balloon tip members.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 873e1aca20
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Add a Clone() method to NOTIFYICONDATA (via MemberwiseClone) and use ShellIconData.Clone() when preparing balloon tip data to avoid mutating the shared NOTIFYICONDATA instance. Also change the BalloonTipIcon dependency property's default from None to Info so balloon tips show an informational icon by default.
| new PropertyMetadata(string.Empty, OnTooltipTextChanged) | ||
| ); | ||
|
|
||
| /// <summary>Identifies the <see cref="BalloonTipTitle"/> dependency property.</summary> |
There was a problem hiding this comment.
These properties should mention in their API docs that text > max size will be cut off.
There was a problem hiding this comment.
You're right, I'll add a comment there to make it clearer.
Add documentation comments to NotifyIcon indicating shell truncation limits for balloon tip title (63 chars) and text (255 chars). Remove unused using directives (including Wpf.Ui.Tray.Internal) in NotifyIcon and several unused usings in ToolTipIcon to tidy code and eliminate warnings. No functional behavior changes.
Add XML documentation noting that balloon tip title and text are truncated by the shell (title: 63 chars, text: 255 chars). Updated summaries in NotifyIcon.ShowBalloonTip and INotifyIcon.BalloonTipTitle/BalloonTipText to clarify these limits so callers and implementers are aware of OS-enforced truncation. Files modified: src/Wpf.Ui.Tray/Controls/NotifyIcon.cs, src/Wpf.Ui.Tray/INotifyIcon.cs.
Replace direct assignments to internalNotifyIconManager.BalloonTipTitle/Text/Icon with SetCurrentValue on the corresponding dependency properties. This preserves existing bindings and avoids overwriting local value sources while still updating the values before calling ShowBalloonTip.
| set => SetValue(TooltipTextProperty, value); | ||
| } | ||
|
|
||
| public string BalloonTipTitle |
There was a problem hiding this comment.
My bad, looks like the documentation needs to be on these properties (not the dependency properties) in order for the XAML editor to surface them
There was a problem hiding this comment.
Do I need to remove the comments on BalloonTipTitleProperty?
| /// Displays a balloon tip notification in the system tray using the current balloon tip properties. | ||
| /// </summary> | ||
| /// <param name="timeout"> | ||
| /// The timeout value, in milliseconds, for displaying the balloon tip notification. |
There was a problem hiding this comment.
nit: this should just be a TimeSpan. Then, you internally call timespan.TotalMilliseconds to convert it to Win32. That way, the public API can be easier to understand
There was a problem hiding this comment.
Okay, I'll switch to using TimeSpan
Change NotifyIcon and InternalNotifyIconManager ShowBalloonTip overloads to accept TimeSpan instead of int (previously milliseconds). Update implementation to use timeout.TotalMilliseconds when populating the native data and refine XML docs: move truncation notes to the BalloonTipTitle/Text properties, clarify duration comments, and simplify icon docs. This is an API-breaking change — update callers to pass a TimeSpan (e.g. TimeSpan.FromMilliseconds(...)). Affected files: NotifyIcon.cs, INotifyIcon.cs, InternalNotifyIconManager.cs.
|
@chucker I'll probably do it when I have some free time. |
Introduce a NotifyIcon demo and service wiring in the Gallery. - Add NotifyIconPage (XAML + code-behind) and NotifyIconViewModel to demonstrate showing balloon tips and updating tooltip text, plus commands and status bindings. - Register INotifyIconService in App DI and add a navigation entry for the new NotifyIcon page in MainWindowViewModel. - Add a named NotifyIcon control to MainWindow and set it into NotifyIconService during window initialization. - Expose an internal manager getter on NotifyIcon to allow the service to attach handlers, and extend INotifyIconService with SetNotifyIcon/GetNotifyIcon methods. - Update NotifyIconService to store the NotifyIcon instance, obtain its internal manager, hook balloon-tip events, and add virtual handlers for balloon tip lifecycle. These changes allow the gallery to showcase tray icon behavior and let the service control and observe the tray icon (balloon tips, tooltip updates, and related events).
|
@chucker I have added a new section "NotifyIcon", please take a moment to check it out.
|
Expose SelectedBalloonTipIcon and BalloonTipIcons in NotifyIconViewModel and use the selected icon when showing the balloon tip. Update NotifyIconPage.xaml to add a ComboBox for choosing the ToolTipIcon, adjust grid rows/margins, and set explicit binding modes (TwoWay for inputs, OneWay for commands/status). These changes let the user pick the balloon tip icon type and improve binding/spacing in the UI.
Remove stored INotifyIconService reference and cache the NotifyIcon instance retrieved from the service in the constructor (throws if null). Wire balloon events to the cached _notifyIcon and use it for ShowBalloonTip. Replace direct TooltipText assignment with SetCurrentValue on the NotifyIcon TooltipTextProperty. Also add commented SetCurrentValue examples for balloon tip properties.
Rename BalloonTipClick and BalloonTipClose identifiers and handlers to BalloonTipClicked and BalloonTipClosed across the tray library and gallery sample. Updated RoutedEvent fields, event accessors, raiser methods (OnBalloonTipClick -> OnBalloonTipClicked, OnBalloonTipClose -> OnBalloonTipClosed), InternalNotifyIconManager event names/invocations, NotifyIconService registrations, and NotifyIconViewModel handler names. This is a non-functional API/identifier cleanup to standardize past-tense naming for balloon tip events.
| [RelayCommand] | ||
| private void OnShowBalloonTip() | ||
| { | ||
| // _notifyIcon.SetCurrentValue(NotifyIcon.BalloonTipTitleProperty, BalloonTipTitle); |
There was a problem hiding this comment.
nit: I assume this was temporary code?
There was a problem hiding this comment.
That comment is another use of Balloon.
There was a problem hiding this comment.
I think I should delete it.
Great, thanks! |
Remove unused System.Drawing using and clean up dead/commented code in NotifyIconViewModel. The previous SetCurrentValue calls for BalloonTip properties were removed and the code now directly calls _notifyIcon.ShowBalloonTip(...) with the duration, title, message and icon, simplifying the balloon tip display logic.





Introduce balloon tip functionality for the tray NotifyIcon. Adds a ToolTipIcon enum and new dependency properties (BalloonTipTitle, BalloonTipText, BalloonTipIcon), routed events (BalloonTipClick, BalloonTipShown, BalloonTipClose) and ShowBalloonTip overloads on NotifyIcon. InternalNotifyIconManager now stores balloon properties, exposes ShowBalloonTip which builds NOTIFYICONDATA (with length limits) and maps icon types to dwInfoFlags, and raises corresponding events. Also wires up native WM message constants in User32 and updates INotifyIcon to include balloon tip members.
Pull request type
Please check the type of change your PR introduces:
What is the current behavior?
Issue Number: #1713
What is the new behavior?
Other information
Here's an example of how BalloonTip's interface is displayed:
