Skip to content

TextCommandBarFlyout: close an empty flyout before it renders - #11718

Draft
Martin Zikmund (MartinZikmund) wants to merge 2 commits into
microsoft:mainfrom
MartinZikmund:user/mzikmund/empty-textcommandbarflyout
Draft

TextCommandBarFlyout: close an empty flyout before it renders#11718
Martin Zikmund (MartinZikmund) wants to merge 2 commits into
microsoft:mainfrom
MartinZikmund:user/mzikmund/empty-textcommandbarflyout

Conversation

@MartinZikmund

Copy link
Copy Markdown
Contributor

Fixes

Fixes #10994

PR Type

  • Bugfix

Description

Right-clicking an empty, editable TextBox with an empty clipboard leaves TextCommandBarFlyout with no commands at all, so it closed itself from its Opened handler. But CommandBarFlyout's Closing handler cancels every close in order to play ClosingOpacityStoryboard first — so instead of never appearing, the empty flyout was drawn and then faded out over ~140 ms. The composition-rendering callback queued from Opening runs after Opened, so it also expanded the command bar, opening the overflow popup on the way out.

Opened is raised after layout but before the frame is rendered, so closing there is early enough — it just must not animate.

CommandBarFlyout now asks a new protected virtual ShouldCloseWithoutShowing() before starting the open animation or raising MenuOpened, and remembers that decision (m_isClosingWithoutShowing) so that:

  • the Closing handler skips the close animation, and
  • the queued composition-rendering callback stops expanding a flyout that has already given up.

TextCommandBarFlyout's existing "no UI to show" condition moves into that override unchanged, which keeps the check at Opened — where apps that add commands from their own Opening handler have already run.

Current Behavior

The empty flyout is rendered and visibly flickers for the duration of the close animation, briefly expanding as it goes.

New Behavior

The empty flyout is never rendered at all. No popup, no flicker.

Customer Impact

User-facing. Fixes the visual glitch reported in #10994 (reproducible in WinUI Gallery's TextBox sample): right-clicking an empty TextBox with an empty clipboard no longer flashes a context menu.

Regression Potential

  • Low risk — isolated change, limited scope

ShouldCloseWithoutShowing() defaults to false, so every CommandBarFlyout other than TextCommandBarFlyout behaves exactly as before. For TextCommandBarFlyout the condition itself is unchanged and still evaluated at the same point in the lifecycle — only the way the flyout closes changes (no animation, and the pending expand callback is skipped).

How Has This Been Tested?

  • I have performed a self-review of my own code
  • I have added tests to cover my changes
  • Existing tests pass locally

The existing ValidateRightClickOnEmptyTextBoxDoesNotShowFlyout interaction test could not catch this bug for three reasons, all fixed in the second commit:

  1. It only counted popups after everything had settled — which is 0 whether or not the flyout flickered on the way. ExtraCommandBarFlyoutPage now counts the frames the flyout was actually on screen for: it subscribes to CompositionTarget.Rendering while the flyout is alive and increments when a popup is open. Rendering is raised right before the frame is drawn, so an open popup there is one the user is about to see.
  2. It never opened the flyout in the first placeInputHelper.RightClick defaults to offset (0,0), the element's top-left corner rather than its centre; on a TextBox that lands on the border and no context menu is requested. It now right-clicks inside the text.
  3. The test app disables long animations at startup, which swaps in a CommandBarFlyoutCommandBar style with the storyboards stripped — and the flicker only existed while the close animation played. The test re-enables animations and restores the setting in a finally.

Verified red/green against the same test binary with only the product DLL swapped: 13 rendered frames without the fix, 0 with it.

Right-clicking an empty, editable TextBox with an empty clipboard leaves
TextCommandBarFlyout with no commands at all, so it closed itself from its
Opened handler. CommandBarFlyout's Closing handler cancels every close to
play the ClosingOpacityStoryboard, so instead of never appearing the empty
flyout was drawn and then faded out over ~140 ms. The composition-rendering
callback queued from Opening runs after Opened, so it also expanded the
command bar, opening the overflow popup on the way out.

Opened is raised after layout but before the frame is rendered, so closing
there is early enough - it just must not animate. CommandBarFlyout now asks
ShouldCloseWithoutShowing() before starting the open animation or raising
MenuOpened, and remembers that decision so the Closing handler skips the
close animation and the queued callback stops expanding a flyout that has
already given up. TextCommandBarFlyout's existing "no UI to show" condition
moves into that override unchanged, which keeps it at Opened where apps that
add commands from their own Opening handler have already run.

Measured on the Extra CommandBarFlyout test page: 13 rendered frames with
the flyout popup open before, 0 after.

Fixes microsoft#10994

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WmxyEHhAWkPxRDbqGHX76Z
…rendered

ValidateRightClickOnEmptyTextBoxDoesNotShowFlyout could not catch microsoft#10994 for
three reasons, all fixed here.

It only counted popups after everything had settled, which is 0 whether or
not the flyout flickered on the way. ExtraCommandBarFlyoutPage now counts the
frames the flyout was actually on screen for: it subscribes to
CompositionTarget.Rendering while the flyout is alive and increments when a
popup is open. Rendering is raised right before the frame is drawn, so an
open popup there is one the user is about to see.

It also never opened the flyout in the first place. InputHelper.RightClick
defaults to offset (0,0), which is the element's top-left corner rather than
its centre; on a TextBox that lands on the border and no context menu is
requested. It now right-clicks inside the text.

Finally, the test app disables long animations at startup, which swaps in a
CommandBarFlyoutCommandBar style with the storyboards stripped - and the
flicker only existed while the close animation played. The test re-enables
animations and restores the setting in a finally.

Verified red/green against the same test binary with only the product DLL
swapped: 13 rendered frames without the fix, 0 with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WmxyEHhAWkPxRDbqGHX76Z
@microsoft-github-policy-service microsoft-github-policy-service Bot added the needs-triage Issue needs to be triaged by the area owners label Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-triage Issue needs to be triaged by the area owners

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Right-clicking an empty TextBox briefly flickers TextCommandBarFlyout

1 participant