Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
147 changes: 147 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue17389.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 17389, "InputTransparent should not affect background color on Windows layouts", PlatformAffected.UWP)]
public class Issue17389 : TestContentPage
{
Grid redGrid;
Grid greenGrid;
Border blueBorder;
ContentView purpleContent;
Label tapCountLabel;
Label redGridLabel;
Label greenGridLabel;
Label blueBorderLabel;
Label purpleContentLabel;
int tapCount;

protected override void Init()
{
tapCountLabel = new Label { Text = "Tap count: 0", HorizontalOptions = LayoutOptions.Center };

redGrid = CreateBackgroundTestGrid(Colors.Red, false, "RedGrid", out redGridLabel);
greenGrid = CreateBackgroundTestGrid(Colors.Green, false, "GreenGrid", out greenGridLabel);

blueBorderLabel = new Label { Text = "Blue Border (InputTransparent=False)", HorizontalOptions = LayoutOptions.Center, AutomationId = "BlueBorder" };
blueBorder = new Border
{
BackgroundColor = Colors.Blue,
InputTransparent = false,
WidthRequest = 200,
HeightRequest = 100,
Content = blueBorderLabel
};
AddTapGesture(blueBorder);

purpleContentLabel = new Label { Text = "Purple Content (InputTransparent=False)", AutomationId = "PurpleContent" };
purpleContent = new ContentView
{
BackgroundColor = Colors.Purple,
InputTransparent = false,
WidthRequest = 200,
HeightRequest = 100,
Content = purpleContentLabel
};
AddTapGesture(purpleContent);

Content = CreateMainContent();
}

ScrollView CreateMainContent()
{
return new ScrollView
{
Content = new StackLayout
{
Spacing = 20,
Children =
{
new Label
{
Text = "InputTransparent Background Test",
FontSize = 18,
FontAttributes = FontAttributes.Bold,
HorizontalOptions = LayoutOptions.Center
},
tapCountLabel,
new Button
{
Text = "Toggle InputTransparent",
Command = new Command(ToggleInputTransparent),
AutomationId = "ToggleInputTransparentButton"
},
new Button
{
Text = "Toggle Background Colors",
Command = new Command(ToggleBackgroundColors),
AutomationId = "ToggleBackgroundColorsButton"
},
redGrid,
greenGrid,
blueBorder,
purpleContent
}
}
};
}

Grid CreateBackgroundTestGrid(Color bgColor, bool inputTransparent, string labelText, out Label label)
{
label = new Label { Text = $"{labelText} (InputTransparent=False)", HorizontalOptions = LayoutOptions.Center, AutomationId = $"{labelText}" };
Comment thread
Dhivya-SF4094 marked this conversation as resolved.
Outdated

Grid childGrid = new Grid
{
BackgroundColor = bgColor,
InputTransparent = inputTransparent,
Children = { label }
};

AddTapGesture(childGrid);

Grid parentGrid = new Grid
{
WidthRequest = 200,
HeightRequest = 100,
InputTransparent = inputTransparent,
BackgroundColor = Colors.LightGray,
Children = { childGrid }
};

AddTapGesture(parentGrid);
return parentGrid;
}

void AddTapGesture(View view)
{
view.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(() =>
{
tapCount++;
tapCountLabel.Text = $"Tap count: {tapCount}";
})
});
}

void ToggleInputTransparent()
{
tapCount = 0;
tapCountLabel.Text = $"Tap count: {0}";
redGrid.InputTransparent = !redGrid.InputTransparent;
greenGrid.InputTransparent = !greenGrid.InputTransparent;
blueBorder.InputTransparent = !blueBorder.InputTransparent;
purpleContent.InputTransparent = !purpleContent.InputTransparent;

redGridLabel.Text = $"Red Grid (InputTransparent={redGrid.InputTransparent})";
greenGridLabel.Text = $"Green Grid (InputTransparent={greenGrid.InputTransparent})";
blueBorderLabel.Text = $"Blue Border (InputTransparent={blueBorder.InputTransparent})";
purpleContentLabel.Text = $"Purple Content (InputTransparent={purpleContent.InputTransparent})";
}

void ToggleBackgroundColors()
{
redGrid.BackgroundColor = Colors.Yellow;
greenGrid.BackgroundColor = Colors.Blue;
blueBorder.BackgroundColor = Colors.LightBlue;
purpleContent.BackgroundColor = Colors.Pink;
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;

public class Issue17389 : _IssuesUITest
{
public Issue17389(TestDevice testDevice) : base(testDevice)
{
}

public override string Issue => "InputTransparent should not affect background color on Windows layouts";

[Test, Order(1)]
[Category(UITestCategories.Layout)]
public void ValidateBackgroundColorDoesNotAffectInputTransparent()
{
App.WaitForElement("ToggleInputTransparentButton");

string[] layouts = new[]
{
"RedGrid",
"GreenGrid",
"BlueBorder",
"PurpleContent"
};

foreach (var layout in layouts)
{
App.Tap(layout);
}

App.WaitForElement("Tap count: 4");
App.Click("ToggleInputTransparentButton");

foreach (var layout in layouts)
{
App.Tap(layout);
}

App.WaitForElement("Tap count: 0");
}

[Test, Order(2)]
[Category(UITestCategories.Layout)]
public void ValidateInputTransparentBackgroundColorToggle()
{
Exception? exception = null;

App.WaitForElement("ToggleBackgroundColorsButton");
VerifyScreenshotOrSetException(ref exception, "BeforeToggleBackgroundColors");
Comment thread
Dhivya-SF4094 marked this conversation as resolved.
Comment thread
Dhivya-SF4094 marked this conversation as resolved.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔍 AI-Generated Review (multi-model)

[major] Regression Prevention / UI Tests — This shared screenshot test runs with environmentName = "windows" on WinUI, but this PR only adds BeforeToggleBackgroundColors/AfterToggleBackgroundColors baselines under Android, iOS, and Mac. There are no matching files under src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows, so the Windows run either fails on a missing baseline or cannot validate the Windows-only regression. Please add the WinUI snapshot baselines (or gate/skip the screenshot verification appropriately).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔍 AI-Generated Review (multi-model)

[moderate] Regression Prevention and Test Coverage — This baseline screenshot is captured before the test enables InputTransparent, so the visual assertions exercise the normal LayoutPanel.Background path rather than the Windows background-layer path changed by this PR. A regression in the added layer sizing/z-order would not be caught here; take at least one screenshot after toggling InputTransparent while the layouts still have non-null backgrounds.

App.WaitForElement("ToggleBackgroundColorsButton");
App.Tap("ToggleBackgroundColorsButton");
VerifyScreenshotOrSetException(ref exception, "AfterToggleBackgroundColors");

if (exception != null)
{
throw exception;
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 20 additions & 10 deletions src/Core/src/Platform/Windows/LayoutPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Microsoft.Maui.Platform
{
public partial class LayoutPanel : MauiPanel
{
const int BackgroundLayerZIndex = int.MinValue;
Canvas? _backgroundLayer;
public bool ClipsToBounds { get; set; }

Expand All @@ -19,6 +20,12 @@ protected override WSize ArrangeOverride(WSize finalSize)
{
var actual = base.ArrangeOverride(finalSize);

if (_backgroundLayer is not null)
{
_backgroundLayer.Measure(finalSize);
_backgroundLayer.Arrange(new WRect(0, 0, finalSize.Width, finalSize.Height));
}

if (!(Parent is ContentPanel contentPanel && contentPanel.BorderStroke?.Shape is not null))
{
Clip = ClipsToBounds ? new RectangleGeometry { Rect = new WRect(0, 0, finalSize.Width, finalSize.Height) } : null;
Expand Down Expand Up @@ -58,7 +65,7 @@ void MakeInputTransparent(Brush? background)

void MakeInputVisible(Brush? background)
{
// If we aren't input transparent, we don't need the background layer hack
// If we aren't input transparent, we don't need the background layer hack
RemoveBackgroundLayer();

if (background == null)
Expand All @@ -74,22 +81,25 @@ void MakeInputVisible(Brush? background)
void AddBackgroundLayer()
{
// In WinUI, once a control has hit testing disabled, all of its child controls
// also have hit testing disabled. The exception is a Panel with its
// also have hit testing disabled. The exception is a Panel with its
// Background Brush set to `null`; the Panel will be invisible to hit testing, but its
// children will work just fine.
// children will work just fine.

// In order to handle the situation where we need the layout to be invisible to hit testing,
// the child controls to be visible to hit testing, *and* we need to support non-null
// background brushes, we insert another empty Panel which is invisible to hit testing; that
// Panel will be our Background brush
// background brushes, we append another empty Panel which is invisible to hit testing; that
// Panel will be our Background brush. We force it behind real layout children using ZIndex.

if (_backgroundLayer != null)
if (_backgroundLayer == null)
{
return;
_backgroundLayer = new Canvas { IsHitTestVisible = false };
Canvas.SetZIndex(_backgroundLayer, BackgroundLayerZIndex);
}

_backgroundLayer = new Canvas { IsHitTestVisible = false };
CachedChildren.Insert(0, _backgroundLayer);
if (!CachedChildren.Contains(_backgroundLayer))
{
CachedChildren.Add(_backgroundLayer);
}
}

void RemoveBackgroundLayer()
Expand All @@ -103,4 +113,4 @@ void RemoveBackgroundLayer()
_backgroundLayer = null;
}
}
}
}
5 changes: 3 additions & 2 deletions src/Core/src/Platform/Windows/ViewExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Microsoft.UI.Xaml.Media;
using WFlowDirection = Microsoft.UI.Xaml.FlowDirection;
using WinPoint = Windows.Foundation.Point;
using WSolidColorBrush = Microsoft.UI.Xaml.Media.SolidColorBrush;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔍 AI-Generated Review (multi-model)

[minor] Complexity Reduction / Dead Code — The WSolidColorBrush alias added here is never referenced anywhere in ViewExtensions.cs. It appears to be a leftover from an earlier revision of this fix (an alias with the same name is already declared independently in LayoutPanel.cs, where it IS used). Remove this unused using directive to avoid confusing future readers about where the alias is actually needed.


namespace Microsoft.Maui.Platform
{
Expand Down Expand Up @@ -439,7 +440,7 @@ public static void UpdateInputTransparent(this FrameworkElement nativeView, IVie

public static void UpdateInputTransparent(this LayoutPanel layoutPanel, ILayoutHandler handler, ILayout layout)
{
// Nothing to do yet, but we might need to adjust the wrapper view
// Nothing to do yet, but we might need to adjust the wrapper view
}
}
}
}
Loading