Skip to content

Fix clipboard service binding for reused diagram views - #12

Merged
Malcolmnixon merged 1 commit into
mainfrom
fix/copy-as-sysml-clipboard-stale-anchor
Jul 20, 2026
Merged

Fix clipboard service binding for reused diagram views#12
Malcolmnixon merged 1 commit into
mainfrom
fix/copy-as-sysml-clipboard-stale-anchor

Conversation

@Malcolmnixon

Copy link
Copy Markdown
Member

This pull request addresses a bug where the "Copy as SysML" feature in the application would always return the snippet from the last-created custom view tab, regardless of which tab was active. The fix ensures that clipboard operations are always correctly anchored to the currently active view, even after tabs are detached and reattached. The changes also add a regression test to prevent this bug from recurring.

Clipboard Service Reliability

  • The clipboard service (AvaloniaClipboardService) now always rebinds to the current view instance in DiagramDocumentView.OnDataContextChanged, ensuring that clipboard operations target the correct, currently attached visual anchor. This prevents clipboard writes from silently failing when a view is reattached after being detached.
  • The clipboard write operation in AvaloniaClipboardService.SetTextAsync is now always marshaled onto the UI thread using Dispatcher.UIThread.InvokeAsync, guaranteeing correctness regardless of the calling thread's context. [1] [2] [3]

Testing and Regression Prevention

  • Added a comprehensive regression test, DiagramContextMenu_CopyAsSysml_TwoCustomViewTabs_EachCopiesItsOwnSnippet, which verifies that each custom view tab copies its own SysML snippet, and that switching between tabs does not result in stale clipboard data. Utility methods for tab selection and clipboard reading were also added to support this test. [1] [2]

The clipboard service on DiagramDocumentView was bound once per
DiagramDocumentViewModel via a null-coalescing assignment (??=). When
Dock recreated/reattached a tab's DiagramDocumentView control while
reusing the same view model (for example creating two custom-view
tabs in quick succession via the View Builder dialog), the clipboard
service stayed anchored to the first, now-detached view instance.
TopLevel.GetTopLevel then resolved null for that anchor, so
SetTextAsync silently no-op'd instead of throwing - the correct
snippet text reached the clipboard call, but never actually reached
the OS clipboard, leaving whatever the last-successfully-bound tab
copied.

Fix: always rebind ClipboardService to the currently-attached view
instance in OnDataContextChanged instead of only the first ever
attached one.

Also hardens AvaloniaClipboardService.SetTextAsync to marshal its
work through Dispatcher.UIThread, since native OS clipboard access
must happen on the UI thread and a caller further up an awaited
chain could otherwise resume on a thread-pool thread.

Adds a regression test that reproduces the original bug end-to-end
through the real Dock-composed MainWindowView (confirmed to fail
before the fix, returning null instead of the first tab's snippet).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Malcolmnixon
Malcolmnixon merged commit 335580d into main Jul 20, 2026
6 checks passed
@Malcolmnixon
Malcolmnixon deleted the fix/copy-as-sysml-clipboard-stale-anchor branch July 21, 2026 00:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant