Skip to content

[Core] Propagate IsEnabled property from Layouts to children#6892

Closed
jsuarezruiz wants to merge 4 commits into
mainfrom
fix-4755
Closed

[Core] Propagate IsEnabled property from Layouts to children#6892
jsuarezruiz wants to merge 4 commits into
mainfrom
fix-4755

Conversation

@jsuarezruiz

Copy link
Copy Markdown
Contributor

Description of Change

Propagate IsEnabled property from Layouts to childrens.

fix-layout-enabled-droid
fix-layout-enabled-windows

Issues Fixed

Fixes #4755
Fixes #5287

@jsuarezruiz jsuarezruiz added t/bug Something isn't working area-layout StackLayout, GridLayout, ContentView, AbsoluteLayout, FlexLayout, ContentPresenter labels May 6, 2022

@Redth Redth left a comment

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.

@jsuarezruiz There are some failing tests on input transparency as a result of this I think.

@mattleibow

Copy link
Copy Markdown
Member

Just had a nasty thought... What happens if we have a layout that we disable, and then manually enable the child in it?

Will it undo the enabled?

Or, if I have a nested grid and disable the outer one and then enable the inner one?

@mattleibow mattleibow left a comment

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.

Since this PR makes changes to child/parent views, we also need to make sure we test these cases:

  • nested layouts
  • disabling a parent and enabling the child
  • disabling the child and enabling the parent
  • disabling a layout and then adding a child
  • any other properties that also enable/disable controls that could potentially conflict with this property
  • since this affects the children, we need tests on moving a child from one layout to another

@jsuarezruiz jsuarezruiz added the do-not-merge Don't merge this PR label May 9, 2022
@jsuarezruiz

Copy link
Copy Markdown
Contributor Author

Added "do-not-merge" label, adding tests.

@Redth Redth added this to the 6.0.300 milestone May 9, 2022
@jsuarezruiz

Copy link
Copy Markdown
Contributor Author

Added new sample:
layout-isenabled-sample

{
platformView.IsHitTestVisible = view.IsEnabled && !view.InputTransparent;

(view as ILayout)?.InvalidateChildrenIsEnabled();

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.

Should this be inside the else block? What happens if Control is also ILayout? If not, then it is a no-op, but if it is...

@Redth Redth left a comment

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.

I fixed the initialization case in android, and fixed the sample to have the "all children disabled" layout actually specify IsEnabled="False"

I tested this on Windows, Android, and MacCatalyst and am now comfortable this works as expected.

@mattleibow mattleibow enabled auto-merge (squash) May 11, 2022 01:57
@mattleibow mattleibow disabled auto-merge May 11, 2022 01:57
@jsuarezruiz

Copy link
Copy Markdown
Contributor Author

Added Device tests.

Comment thread src/Core/src/Core/IView.cs Outdated
@rmarinho rmarinho removed the do-not-merge Don't merge this PR label May 11, 2022

@Redth Redth left a comment

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.

This one needs some more thought after some conversation with @mattleibow and failing tests...

@Redth Redth marked this pull request as draft May 11, 2022 20:52
@Redth Redth modified the milestones: 6.0.300, 6.0.300-servicing May 11, 2022
@jsuarezruiz

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 2 pipeline(s).

{
public static void InvalidateChildrenIsEnabled(this ILayout layout)
{
foreach (var children in layout.OrderByZIndex())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Even if this were the correct place to do it, there's no reason to enable/disable the children in z-index order.

@hartez hartez left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What happens if we have a layout that we disable, and then manually enable the child in it?

Core is the wrong place to implement these rules. Core should handle mapping IsEnabled -> platformView.IsEnabled (or whatever the platform equivalent is) and nothing else. Any sort of propagation is the business of the implementing SDK.

At the Controls level, we should implement whatever propagation we had in Forms (for consistency). IIRC, in Forms a Layout with IsEnabled == false meant that all child controls are also effectively disabled. Any attempt to "enable" a child of disabled Layout does nothing. We should verify that, and we would need to implement that at the Controls level.

Other SDKs may want more permissive enable/disable rules (like bulk disabling a Layout and then enabling a single child) - and they'd be free to handle it that way.

@hartez hartez changed the title [Core] Propagate IsEnabled property from Layouts to childrens [Core] Propagate IsEnabled property from Layouts to children Jul 19, 2022
@Redth Redth modified the milestones: 6.0-servicing, .NET 7 Planning Aug 30, 2022
@jsuarezruiz jsuarezruiz changed the base branch from net6.0 to main December 14, 2022 09:07
@jsuarezruiz jsuarezruiz changed the base branch from main to net6.0 December 14, 2022 09:08
@jsuarezruiz jsuarezruiz changed the base branch from net6.0 to main December 14, 2022 13:04
@jsuarezruiz jsuarezruiz marked this pull request as ready for review December 14, 2022 13:04
@jsuarezruiz

Copy link
Copy Markdown
Contributor Author

Changed target to main. Tested and passed the device tests in the different platforms.
image

@hartez hartez left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

None of the propagation should be happening in Core; that should be left to the implementing SDK. And Controls should be implementing this in a way that matches Forms, for backward compatibility.

Comment thread src/Core/src/Extensions/IViewExtensions.cs Outdated
@rmarinho

rmarinho commented Jan 2, 2023

Copy link
Copy Markdown
Member

Not sure if i agree, that the propagation should not be on the Core. What's the reason for that? that's not a sdk rule, that should be a layout rule, if a layout is disable the children are disable, it's a general rule for all sdks. not a form specific.

@hartez

hartez commented Jan 3, 2023

Copy link
Copy Markdown
Contributor

Not sure if i agree, that the propagation should not be on the Core. What's the reason for that? that's not a sdk rule, that should be a layout rule, if a layout is disable the children are disable, it's a general rule for all sdks. not a form specific.

Because reasonable people can disagree on what the rules should be. For example, look at the questions in Matt's comment - there's no obviously right answer to these.

Choosing a set of answers and making Core opionated about how enabling/disabling containers should work adds complexity to Core and impacts performance. And it forces every other SDK implementation to either use those rules or spend a lot of effort working around them.

Core should be providing simple, basic infrastructure that's not especially opinionated. And the simplest possible mapping of IsEnabled to the containers is to do nothing.

This gives us the flexibility to answer all of those questions in Controls in whatever way we choose, whether it's by replicating the weirdness of Forms for backward compatibility, or doing something simpler and less confusing.

@hartez

hartez commented Jan 7, 2023

Copy link
Copy Markdown
Contributor

Okay, after thinking about this some more, I think it's fine for us to put this in Core with some modifications. If we don't force any disabling in the backing layouts themselves, this is easy enough for 3rd party implementations to change if they want to.

@hartez hartez left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

On further reflection, I think this will be fine. We just need to make some adjustments.

{
internal static void InvalidateChildrenIsEnabled(this ILayout layout)
{
foreach (var children in layout.GetChildren())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

layout is already an IList<IView>, so we don't need the GetChildren() method here. And this should be a for loop rather than a foreach, for performance reasons.

{
internal static class LayoutExtensions
{
public static IList<IView> GetChildren(this ILayout layout) => layout;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This method isn't necessary.

if (platformView is UIControl uiControl)
uiControl.Enabled = view.GetIsEnabled();

if (platformView is LayoutView layout)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We don't need to enable/disable the layout backing controls; the child controls will all be disabled anyway. We can just drop lines 26 & 27,

return result;
}

internal bool InternalUserInteractionEnabled

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We don't need to disable user interaction, so this property can just go away.

if (platformView is Control control)
control.UpdateIsEnabled(view);
else
platformView.IsHitTestVisible = view.GetIsEnabled() && !view.InputTransparent;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We don't need to block input to the layout backing control here; lines 34 & 35 can go.

public static void UpdateIsEnabled(this FrameworkElement platformView, IView view)
{
if (platformView is Control control)
control.UpdateIsEnabled(view);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We can probably change this to control.IsEnabled = view.GetIsEnabled() and avoid creating another extension method.

platformControl.IsTextScaleFactorEnabled = font.AutoScalingEnabled;
}

public static void UpdateIsEnabled(this Control platformControl, IView view) =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the only place using this method is ViewExtensions.cs below, we can probably just inline this and avoid adding more API.

@mattleibow

Copy link
Copy Markdown
Member

We are probably going to use v10 :) #12488

@mattleibow mattleibow closed this Jan 12, 2023
@mattleibow mattleibow deleted the fix-4755 branch January 12, 2023 17:46
@github-actions github-actions Bot locked and limited conversation to collaborators Dec 22, 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 t/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

StackLayout IsEnabled Property does not work IsEnabled not working properly for layout

5 participants