Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
5 changes: 4 additions & 1 deletion src/Controls/src/Core/Element/Element.cs
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ protected override void OnPropertyChanged([CallerMemberName] string propertyName
{
base.OnPropertyChanged(propertyName);

Handler?.UpdateValue(propertyName);
UpdateHandlerValue(propertyName);

if (_effects?.Count > 0)
{
Expand All @@ -583,6 +583,9 @@ protected override void OnPropertyChanged([CallerMemberName] string propertyName
}
}

private protected virtual void UpdateHandlerValue(string property) =>
Handler?.UpdateValue(property);

internal IEnumerable<Element> Descendants() =>
Descendants<Element>();

Expand Down
13 changes: 13 additions & 0 deletions src/Controls/src/Core/VisualElement/VisualElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1942,6 +1942,19 @@ static double EnsurePositive(double value)
return value;
}

private protected override void UpdateHandlerValue(string property)
{
// The Height and Width properties aren't really meant to propagate back down to the handler.
// These properties are only set when the platform code updates the VisualElement.Frame property
// during an arrange pass, indicating what the actual width and height of the platform element are.
// WidthRequest and HeightRequest are the properties that we use to propagate changes down to the handler.
// These will still propagate down to the handler via the `OnRequestChanged` method.
if (this.Batched && (property == HeightProperty.PropertyName || property == WidthProperty.PropertyName))
return;

base.UpdateHandlerValue(property);
}

/// <inheritdoc/>
double IView.Width
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Threading.Tasks;
using Microsoft.Maui.Animations;

using Microsoft.Maui.Handlers;

namespace Microsoft.Maui.Controls.Core.UnitTests
{
public class BasicVisualElement : VisualElement
{
}

public class BasicVisualElementHandler : ViewHandler<BasicVisualElement, object>
{
public BasicVisualElementHandler(IPropertyMapper mapper, CommandMapper commandMapper = null) : base(mapper, commandMapper)
{
}

protected override object CreatePlatformView()
{
return new object();
}
}
}
83 changes: 83 additions & 0 deletions src/Controls/tests/Core.UnitTests/VisualElementTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
using System.Data.Common;
using System.Threading.Tasks;
using Microsoft.Maui.Controls.Shapes;

using Microsoft.Maui.Controls.Hosting;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Platform;

using Microsoft.Maui.Handlers;
using Microsoft.Maui.Primitives;
using Xunit;
Expand Down Expand Up @@ -237,5 +242,83 @@ public async Task ShadowDoesNotLeak()

Assert.False(reference.IsAlive, "VisualElement should not be alive!");
}

[Fact]
public void HandlerDoesntPropagateWidthChangesDuringBatchUpdates()
{
bool mapperCalled = false;

var mapper = new PropertyMapper<IView, ViewHandler>(ViewHandler.ViewMapper)
{
[nameof(IView.Height)] = (_,_) => mapperCalled = true,
[nameof(IView.Width)] = (_,_) => mapperCalled = true,
};

var mauiApp1 = MauiApp.CreateBuilder()
.UseMauiApp<ApplicationStub>()
.ConfigureMauiHandlers(handlers => handlers.AddHandler<BasicVisualElement>((services) => new BasicVisualElementHandler(mapper)))
.Build();

var element = new BasicVisualElement();
var platformView = element.ToPlatform(new MauiContext(mauiApp1.Services));

mapperCalled = false;
element.Frame = new Rect(0,0,100,100);
Assert.False(mapperCalled);
}

[Fact]
public void HandlerDoesPropagateWidthChangesWhenUpdatedDuringSizedChanged()
{
bool mapperCalled = false;

var mapper = new PropertyMapper<IView, ViewHandler>(ViewHandler.ViewMapper)
{
[nameof(IView.Height)] = (_,_) => mapperCalled = true,
[nameof(IView.Width)] = (_,_) => mapperCalled = true,
};

var mauiApp1 = MauiApp.CreateBuilder()
.UseMauiApp<ApplicationStub>()
.ConfigureMauiHandlers(handlers => handlers.AddHandler<BasicVisualElement>((services) => new BasicVisualElementHandler(mapper)))
.Build();

var element = new BasicVisualElement();
var platformView = element.ToPlatform(new MauiContext(mauiApp1.Services));

element.SizeChanged += (_,_) => element.HeightRequest = 100;
mapperCalled = false;
element.Frame = new Rect(0,0,100,100);

Assert.True(mapperCalled);
}

[Fact]
public void WidthAndHeightRequestPropagateToHandler()
{
bool mapperCalled = false;

var mapper = new PropertyMapper<IView, ViewHandler>(ViewHandler.ViewMapper)
{
[nameof(IView.Height)] = (_,_) => mapperCalled = true,
[nameof(IView.Width)] = (_,_) => mapperCalled = true,
};

var mauiApp1 = MauiApp.CreateBuilder()
.UseMauiApp<ApplicationStub>()
.ConfigureMauiHandlers(handlers => handlers.AddHandler<BasicVisualElement>((services) => new BasicVisualElementHandler(mapper)))
.Build();

var element = new BasicVisualElement();
var platformView = element.ToPlatform(new MauiContext(mauiApp1.Services));

mapperCalled = false;
element.WidthRequest = 99;
Assert.True(mapperCalled);
Comment thread
PureWeen marked this conversation as resolved.
Outdated

mapperCalled = false;
element.HeightRequest = 99;
Assert.True(mapperCalled);
}
}
}