[Proposal] OnVisualState markup extension #3214
matt-goldman
started this conversation in
New Feature Discussions
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
OnVisualStatemarkup extension: collocated visual state declarationsVisual State Manager is incredibly powerful but also convoluted, requiring substantial boilerplate for something that could be expressed much more simply. I'd like to propose an
OnVisualStatemarkup extension that follows the same pattern established byAppThemeBinding: replacing a verbose, structurally separated approach with a collocated, declarative one.The problem
Take the following example. This is a control used in a list of search results; each item can be selected to add to a collection. The visual requirements are to remove the default selection background and show a check icon when selected.
There are two problems with this:
CheckLabel.IsVisibledoes, you have to read the property on the label, then jump to the VSM block at the top of the file (or worse, in a separate style/resource dictionary), then mentally merge them. This structural separation makes maintenance harder and makes the XAML harder to reason about at a glance.Proposed solution
An
OnVisualStatemarkup extension that collocates state-dependent values with the properties they apply to, the same thingAppThemeBindingdid for theme-dependent values.This solves both problems:
CheckLabel.IsVisibleisFalseinNormalandTrueinSelected, right where the property is declared.Behaviour
BackgroundColor="{OnVisualState Selected=Transparent}"means: in theSelectedstate, setBackgroundColortoTransparent; in all other states, leave it at whatever value it would otherwise have (inherited, default, or explicitly set). This is consistent with howTriggerandDataTriggeralready behave, when the condition is no longer met, the property reverts, and eliminates an entire class of VSM bug where forgetting to define aNormalsetter leaves a property stuck on the value from another state.CommOnVisualStatesby default, with an optionalGroupparameter for custom state groups.{OnVisualState Normal={StaticResource Gray500}, Focused={StaticResource Primary}}should work the same way nested extensions work withAppThemeBinding.Precedent
This follows the pattern established by
AppThemeBinding, which replaced manualRequestedThemeChangedhandling with a collocated, declarative markup extension. The motivations are the same: less boilerplate, better collocation, easier maintenance, applied to visual states instead of themes.Relationship to C# XAML expressions
XAML C# expressions (slated for .NET 11) will make many things easier, and it's worth considering whether they'd make this unnecessary. My current thinking is that even if an expression could inspect visual state and return a value,
OnVisualStatewould still be a valid addition for two reasons:OnVisualStateis vocabulary that extends the declarative surface; an expression is a workaround through imperative code.AppThemeBindingexists despite the fact that you can handle theming in code-behind, because the declarative form is more idiomatic and easier to maintain.OnVisualStateinstances, lifecycle tied to element attach/detach, no reflection at evaluation time). A general-purpose expression mechanism can't make those assumptions.Status
I've started dabbling with a prototype, nothing I particularly want to share yet. This is something I'll use for sure but wanted to gauge community appetite for something like this in the toolkit.
All reactions