Skip to content

Toggle IsEnabled on Layout children when IsEnabled changes#12365

Closed
hartez wants to merge 1 commit into
mainfrom
fix-5287
Closed

Toggle IsEnabled on Layout children when IsEnabled changes#12365
hartez wants to merge 1 commit into
mainfrom
fix-5287

Conversation

@hartez

@hartez hartez commented Dec 30, 2022

Copy link
Copy Markdown
Contributor

Description of Change

Offering this as an alternative to #6892.

This change modifies the Layouts in MAUI.Controls to toggle the IsEnabled property of all their children whenever the IsEnabled property of the Layout is changed.

This change deliberately avoids handling IsEnabled on Layouts in the Core layer; as far as Core is concerned, IsEnabled has no effect on Layouts at all. This leaves the option for implementing SDKs to make their own decisions on question about how enabling/disabling Layouts should affect child controls (questions like the ones posed in this comment).

As for the Controls layer, this implementation is very simple; when a Layout's IsEnabled property is set to false, all of its children have their IsEnabled property set to false. When the Layout's property is set to true, the children's properties are set to true. This differs from the Forms implementation in several ways, which I would argue are improvements.

In Forms, child controls are unaffected when Layout.IsEnabled is set to false. Rather, touch input to the backing control (DefaultRenderer) is blocked entirely. This effectively disables interaction with the controls via touch, but in some cases other interaction (keyboard, voice command, etc.) is still possible. This is confusing. The implementation in the PR actually disables the child controls, preventing accidental interactions.

Also, the child controls in Forms are not visibly disabled; they retain their "enabled" visual states. Since this PR's implementation actually disables the controls, they apply their platform "disabled" visuals, and they have their cross-platform "disabled" visual states applied.

In Forms, interrogating the IsEnabled properties of child controls will return true even though they've been effectively (sort of) disabled. This PR will return non-confusing values when checking IsEnabled on child controls.

One major divergence from Forms is the option to re-enable a child control which has been disabled by disabling its container. This provides a flexibility that Forms did not.

Issues Fixed

Fixes #5287

@Eilon Eilon added the area-layout StackLayout, GridLayout, ContentView, AbsoluteLayout, FlexLayout, ContentPresenter label Jan 3, 2023
{
if (this[n] is VisualElement visualElement)
{
visualElement.IsEnabled = isEnabled;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we modify the properties like this? Won't this remove any bindings the user has defined for IsEnabled on any child elements?

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.

It would bypass those bindings, yes. The next question would be whether that's a concern.

If it is, then we have a couple of options:

  • We could determine if there's a way to check whether the property was bound before setting it, and skip it in that case.
  • We could go with the Forms behavior of simply disabling input on the Layout/ContentView, with the attendant problems (no visual indication that child controls are "disabled", etc.)

@mattleibow

Copy link
Copy Markdown
Member

One question I have is on this last statement:

One major divergence from Forms is the option to re-enable a child control which has been disabled by disabling its container. This provides a flexibility that Forms did not.

Is this a good thing?

Assume I have some set of controls all data bound - buttons with CanExecute and Entries based on some check box. Then I have some larger toggle that disables the entire form. When I re-enable the form, will all the controls become enabled? And what happens if there is logic that is enabling and disabling controls based based on data, but the whole form is disabled. Will the controls become enabled even though I have explicitly disable the entire form?

@hartez

hartez commented Jan 7, 2023

Copy link
Copy Markdown
Contributor Author

One question I have is on this last statement:

One major divergence from Forms is the option to re-enable a child control which has been disabled by disabling its container. This provides a flexibility that Forms did not.

Is this a good thing?

Assume I have some set of controls all data bound - buttons with CanExecute and Entries based on some check box. Then I have some larger toggle that disables the entire form. When I re-enable the form, will all the controls become enabled? And what happens if there is logic that is enabling and disabling controls based based on data, but the whole form is disabled. Will the controls become enabled even though I have explicitly disable the entire form?

As it is right now, this implementation will definitely disable/enable controls with no concern for any pre-existing bindings. As I mentioned in reply to Shane's comment, we could look at adding a check for "is this property bound" before modifying it (not sure whether this is possible or performant, I'd have to look into it).

This implementation also does nothing when a new control is added to a disabled Layout/ContentView, which will probably need to be addressed.

Or we could go back to the Forms behavior where we disable input for the entire Layout/ContentView, and enabling/disabling a Layout/ContentView has no actual effect on the controls within it. It's easy enough to do that in Controls, but we'll retain all of the confusing parts, too.

A third alternative would be to change the mapping of the xplat IsEnabled property to be IView.IsEnabled ANDed with a check up the tree for any disabled container. So instead of setting VisualElement.IsEnabled on all children when we enable/disable a Layout/ContentView, we'd call mapper.UpdateValue("IsEnabled"), and let the mapper sort out the result.

Actually, I like that last option a lot - gonna give that a try.

@hartez hartez marked this pull request as draft January 7, 2023 00:05
@hartez

hartez commented Jan 7, 2023

Copy link
Copy Markdown
Contributor Author

Making this a draft while I try out another option.

@hartez hartez closed this Jan 7, 2023
@hartez hartez deleted the fix-5287 branch February 10, 2023 19:10
@github-actions github-actions Bot locked and limited conversation to collaborators Dec 14, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-layout StackLayout, GridLayout, ContentView, AbsoluteLayout, FlexLayout, ContentPresenter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

StackLayout IsEnabled Property does not work

4 participants