Skip to content

feat(tray): Add balloon tip support to NotifyIcon#1715

Open
maihcx wants to merge 13 commits into
lepoco:mainfrom
maihcx:#1713
Open

feat(tray): Add balloon tip support to NotifyIcon#1715
maihcx wants to merge 13 commits into
lepoco:mainfrom
maihcx:#1713

Conversation

@maihcx
Copy link
Copy Markdown
Contributor

@maihcx maihcx commented May 14, 2026

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:

  • Update
  • Bugfix
  • Feature
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • Documentation content changes

What is the current behavior?

Issue Number: #1713

What is the new behavior?

  • Added new properties and functionality related to BalloonTip to support displaying notifications as popups for NotifyIcon.

Other information

Here's an example of how BalloonTip's interface is displayed:
image

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.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/Wpf.Ui.Tray/Internal/InternalNotifyIconManager.cs
Comment thread src/Wpf.Ui.Tray/Internal/InternalNotifyIconManager.cs Outdated
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.
@maihcx maihcx changed the title feat(controls): Add balloon tip support to NotifyIcon feat(tray): Add balloon tip support to NotifyIcon May 14, 2026
Copy link
Copy Markdown
Collaborator

@chucker chucker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't tested, but superficially lgtm.

My main concern here is that Wpf.Ui.Tray now has even more brittle Win32 code. A (separate) PR that replaces that with LibraryImport or CsWin32 would be good.

Tested, works:

image

new PropertyMetadata(string.Empty, OnTooltipTextChanged)
);

/// <summary>Identifies the <see cref="BalloonTipTitle"/> dependency property.</summary>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These properties should mention in their API docs that text > max size will be cut off.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I'll add a comment there to make it clearer.

maihcx added 2 commits May 14, 2026 15:51
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.
@maihcx maihcx requested a review from chucker May 14, 2026 09:01
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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I need to remove the comments on BalloonTipTitleProperty?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, those now yield "should have standard documentation text" warnings for me:

image

So just revert them to their defaults.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay

/// 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.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I'll switch to using TimeSpan

Copy link
Copy Markdown
Collaborator

@chucker chucker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall lgtm. Thank you for your contribution!

Can you perhaps expand the Gallery app in the System section:

Image

…with a new section "NotifyIcon" that just has a button to show a sample balloon tip.

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.
@maihcx
Copy link
Copy Markdown
Contributor Author

maihcx commented May 14, 2026

@chucker I'll probably do it when I have some free time.

@maihcx maihcx requested a review from chucker May 14, 2026 10:01
@github-actions github-actions Bot added the gallery WPF UI Gallery label May 15, 2026
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).
@maihcx
Copy link
Copy Markdown
Contributor Author

maihcx commented May 15, 2026

@chucker I have added a new section "NotifyIcon", please take a moment to check it out.

image

maihcx added 3 commits May 15, 2026 10:27
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);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I assume this was temporary code?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That comment is another use of Balloon.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I should delete it.

@chucker
Copy link
Copy Markdown
Collaborator

chucker commented May 15, 2026

@chucker I have added a new section "NotifyIcon", please take a moment to check it out.

image

Great, thanks!

maihcx added 2 commits May 15, 2026 15:04
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dotnet gallery WPF UI Gallery PR Pull request release tray

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants