Skip to content

Rename a state: update animation keyframe references and clear stale error (#3383)#3393

Closed
vchelaru wants to merge 2 commits into
mainfrom
3383-rename-state-anim
Closed

Rename a state: update animation keyframe references and clear stale error (#3383)#3393
vchelaru wants to merge 2 commits into
mainfrom
3383-rename-state-anim

Conversation

@vchelaru

@vchelaru vchelaru commented Jun 27, 2026

Copy link
Copy Markdown
Owner

Summary

Renaming a state did not reliably update animations that referenced it: the keyframe kept pointing at the old name, leaving a lingering Keyframe at time … references a state X which does not exist error (surfaced on the tree node and Errors tab after #3293/#3382). Fixes #3383.

The pre-fix symptom was deceptive: the error vanished the instant you renamed (the WPF binding nulled StateName, which trips neither error branch), so it looked fixed — but the keyframe was never actually rewritten, and re-selecting/reloading the element rebuilt the original reference and the error returned.

Root causes addressed

  1. Plugin orderingMainStateAnimationPlugin.HandleStateRename called RefreshViewModel() (which recomputes/broadcasts errors against the still-old keyframe names) before RenameManager rewrote the keyframes, and never recomputed afterward. Reordered: rewrite first, then RefreshViewModel recomputes + rebroadcasts.
  2. WPF binding nulled the reference — rebuilding AvailableStates removed the old categorized name, so the keyframe ComboBox's two-way SelectedItemStateName binding cleared StateName to null before the rewrite could match it. The post-rename name is now seeded into AvailableStates before the rewrite, so the binding accepts the rewritten value instead of nulling it.
  3. Prefix via ToString() — the category prefix was built from StateSaveCategory.ToString() instead of .Name; switched to .Name to match the rest of the keyframe-name handling.

Persistence — single save path (no double write)

RenameManager.HandleRename(StateSave) rewrites the keyframe and does not save. Assigning keyframe.StateName raises PropertyChanged, which the plugin already persists through its centralized HandleDataChange (AnyChange) save — the same single path the sibling InstanceSave overload relies on. An explicit save here would write the .ganx twice per rename and trip external (and Gum's own) file watchers on a change that already settled. The ElementSave overload still saves explicitly because renaming the element file changes no keyframe property, so nothing triggers the implicit save there.

Tests

All 18 StateAnimationPlugin tests green; GumFull.sln builds with 0 errors.

Manual verification

The WPF ComboBox-binding half can't be unit-tested (needs a WPF host), so it's verified in the running tool: add a state (in a category), create an animation keyframe referencing it, rename the state → no missing-state error appears, the keyframe shows the new name, and it persists across reselect/reload.

Closes #3383

🤖 Generated with Claude Code

…error (#3383)

Renaming a state left animation keyframes pointing at the old name, producing a lingering 'references a state X which does not exist' error.

Three root causes, all addressed:

- MainStateAnimationPlugin.HandleStateRename refreshed the view model (recomputing/broadcasting errors against the still-old keyframe names) BEFORE rewriting the keyframes, and never recomputed afterward. Reordered: rewrite keyframes first, then RefreshViewModel recomputes errors and rebroadcasts. The post-rename name is seeded into AvailableStates before the rewrite so the keyframe ComboBox's two-way SelectedItem binding does not null the (now-absent) old selection.

- RenameManager.HandleRename(StateSave) did not persist the .ganx (unlike the ElementSave overload), so even a corrected reference could be lost on reload. It now saves when a keyframe was rewritten.

- RenameManager.HandleRename(StateSave) built the category prefix via StateSaveCategory.ToString() rather than .Name; switched to .Name to match the rest of the keyframe name handling.

Tests: added RenameManager persistence coverage (saves on a referenced-state rename, does not save when nothing matches); promoted the categorized-state rename test to the #3383 ordering regression guard and removed the now-fixed stale-error characterization test. The WPF ComboBox-binding half is verified manually.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Removed the explicit Save() added to RenameManager.HandleRename(StateSave). Assigning keyframe.StateName already raises PropertyChanged, which the plugin persists via its centralized HandleDataChange (AnyChange) save — the same single path the sibling InstanceSave overload relies on. A second explicit save wrote the .ganx twice per rename, which can trip external tools' file watchers (and Gum's own IFileWatchManager) on a change that already settled. Documented why the ElementSave overload still saves explicitly (element-file rename changes no keyframe property, so nothing triggers the implicit save there). Reverted the two RenameManager persistence tests that asserted the now-removed save.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vchelaru

Copy link
Copy Markdown
Owner Author

Closing as redundant. #3383 was already fixed at the root by #3389 (merged onto the same base this branch was cut from, mid-session): the keyframe state ComboBox was made IsEditable with a Text binding, eliminating the StateName null-coercion entirely, plus the HandleStateRename ordering fix. This PR re-introduced the AvailableStates-seeding workaround that #3389 deliberately reverted, so merging it would regress that design.

@vchelaru vchelaru closed this Jun 27, 2026
@vchelaru vchelaru deleted the 3383-rename-state-anim branch June 27, 2026 23:33
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.

Renaming a state doesn't update animation keyframe references (leaves a stale missing-state error)

1 participant