Skip to content

Commit 5573017

Browse files
committed
Skip useless handler mappings calls while connecting
1 parent 5ceff42 commit 5573017

File tree

11 files changed

+244
-9
lines changed

11 files changed

+244
-9
lines changed

src/Controls/src/Core/Label/Label.Mapper.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public partial class Label
2121

2222
// these are really a single property
2323
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(Text), MapText);
24-
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(FormattedText), MapText);
24+
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(FormattedText), MapFormattedText);
2525

2626
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(LineBreakMode), MapLineBreakMode);
2727
LabelHandler.Mapper.ReplaceMapping<Label, ILabelHandler>(nameof(MaxLines), MapMaxLines);
@@ -54,8 +54,17 @@ public static void MapTextType(ILabelHandler handler, Label label) =>
5454
MapTextOrFormattedText(handler, label);
5555
static void MapTextTransform(ILabelHandler handler, Label label) =>
5656
MapTextOrFormattedText(handler, label);
57+
static void MapFormattedText(ILabelHandler handler, Label label)
58+
{
59+
if (label.IsConnectingHandler()) return;
60+
61+
MapText(handler, label);
62+
}
63+
5764
static void MapTextOrFormattedText(ILabelHandler handler, Label label)
5865
{
66+
if (label.IsConnectingHandler()) return;
67+
5968
if (label.HasFormattedTextSpans)
6069
handler.UpdateValue(nameof(FormattedText));
6170
else
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
4+
namespace Microsoft.Maui
5+
{
6+
internal static class InternalElementExtensions
7+
{
8+
/// <summary>
9+
/// The handler is connecting for the first time to the element and mapping all properties.
10+
/// </summary>
11+
/// <param name="element"></param>
12+
/// <returns></returns>
13+
internal static bool IsMappingProperties(this IElement element) =>
14+
(element.Handler as IElementHandlerStateExhibitor)?.State.HasFlag(ElementHandlerState.MappingProperties) ?? false;
15+
16+
/// <summary>
17+
/// Indicates whether the handler is connecting for the first time to the element and mapping all properties.
18+
/// </summary>
19+
/// <param name="element"></param>
20+
/// <returns></returns>
21+
internal static bool IsConnectingHandler(this IElement element) =>
22+
(element.Handler as IElementHandlerStateExhibitor)?.State.HasFlag(ElementHandlerState.Connecting) ?? false;
23+
24+
/// <summary>
25+
/// Indicates whether the connected handler is now connecting to a new element and updating properties.
26+
/// </summary>
27+
/// <param name="element"></param>
28+
/// <returns></returns>
29+
internal static bool IsReconnectingHandler(this IElement element) =>
30+
(element.Handler as IElementHandlerStateExhibitor)?.State.HasFlag(ElementHandlerState.Reconnecting) ?? false;
31+
}
32+
}

src/Core/src/Handlers/Border/BorderHandler.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,25 @@ public static void MapBackground(IBorderHandler handler, IBorderView border)
8686
((PlatformView?)handler.PlatformView)?.UpdateBackground(border);
8787
}
8888

89+
private static bool ShouldSkipStrokeMappings(IBorderHandler handler) {
90+
#if __IOS__ || MACCATALYST || ANDROID
91+
// During the initial connection, the `MapBackground` takes care of updating the stroke properties
92+
// so we can skip the stroke mappings to avoid repetitive and useless updates.
93+
return handler.IsConnectingHandler();
94+
#else
95+
return false;
96+
#endif
97+
}
98+
8999
/// <summary>
90100
/// Maps the abstract <see cref="IBorderStroke.Shape"/> property to the platform-specific implementations.
91101
/// </summary>
92102
/// <param name="handler">The associated handler.</param>
93103
/// <param name="border">The associated <see cref="IBorderView"/> instance.</param>
94104
public static void MapStrokeShape(IBorderHandler handler, IBorderView border)
95105
{
106+
if (ShouldSkipStrokeMappings(handler)) return;
107+
96108
((PlatformView?)handler.PlatformView)?.UpdateStrokeShape(border);
97109
MapBackground(handler, border);
98110
}
@@ -104,6 +116,8 @@ public static void MapStrokeShape(IBorderHandler handler, IBorderView border)
104116
/// <param name="border">The associated <see cref="IBorderView"/> instance.</param>
105117
public static void MapStroke(IBorderHandler handler, IBorderView border)
106118
{
119+
if (ShouldSkipStrokeMappings(handler)) return;
120+
107121
((PlatformView?)handler.PlatformView)?.UpdateStroke(border);
108122
MapBackground(handler, border);
109123
}
@@ -115,6 +129,8 @@ public static void MapStroke(IBorderHandler handler, IBorderView border)
115129
/// <param name="border">The associated <see cref="IBorderView"/> instance.</param>
116130
public static void MapStrokeThickness(IBorderHandler handler, IBorderView border)
117131
{
132+
if (ShouldSkipStrokeMappings(handler)) return;
133+
118134
((PlatformView?)handler.PlatformView)?.UpdateStrokeThickness(border);
119135
MapBackground(handler, border);
120136
}
@@ -126,6 +142,8 @@ public static void MapStrokeThickness(IBorderHandler handler, IBorderView border
126142
/// <param name="border">The associated <see cref="IBorderView"/> instance.</param>
127143
public static void MapStrokeLineCap(IBorderHandler handler, IBorderView border)
128144
{
145+
if (ShouldSkipStrokeMappings(handler)) return;
146+
129147
((PlatformView?)handler.PlatformView)?.UpdateStrokeLineCap(border);
130148
}
131149

@@ -136,6 +154,8 @@ public static void MapStrokeLineCap(IBorderHandler handler, IBorderView border)
136154
/// <param name="border">The associated <see cref="IBorderView"/> instance.</param>
137155
public static void MapStrokeLineJoin(IBorderHandler handler, IBorderView border)
138156
{
157+
if (ShouldSkipStrokeMappings(handler)) return;
158+
139159
((PlatformView?)handler.PlatformView)?.UpdateStrokeLineJoin(border);
140160
}
141161

@@ -146,6 +166,8 @@ public static void MapStrokeLineJoin(IBorderHandler handler, IBorderView border)
146166
/// <param name="border">The associated <see cref="IBorderView"/> instance.</param>
147167
public static void MapStrokeDashPattern(IBorderHandler handler, IBorderView border)
148168
{
169+
if (ShouldSkipStrokeMappings(handler)) return;
170+
149171
((PlatformView?)handler.PlatformView)?.UpdateStrokeDashPattern(border);
150172
}
151173

@@ -156,6 +178,8 @@ public static void MapStrokeDashPattern(IBorderHandler handler, IBorderView bord
156178
/// <param name="border">The associated <see cref="IBorderView"/> instance.</param>
157179
public static void MapStrokeDashOffset(IBorderHandler handler, IBorderView border)
158180
{
181+
if (ShouldSkipStrokeMappings(handler)) return;
182+
159183
((PlatformView?)handler.PlatformView)?.UpdateStrokeDashOffset(border);
160184
}
161185

@@ -166,6 +190,8 @@ public static void MapStrokeDashOffset(IBorderHandler handler, IBorderView borde
166190
/// <param name="border">The associated <see cref="IBorderView"/> instance.</param>
167191
public static void MapStrokeMiterLimit(IBorderHandler handler, IBorderView border)
168192
{
193+
if (ShouldSkipStrokeMappings(handler)) return;
194+
169195
((PlatformView?)handler.PlatformView)?.UpdateStrokeMiterLimit(border);
170196
}
171197

src/Core/src/Handlers/Element/ElementHandler.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Microsoft.Maui.Handlers
44
{
5-
public abstract partial class ElementHandler : IElementHandler
5+
public abstract partial class ElementHandler : IElementHandler, IElementHandlerStateExhibitor
66
{
77
public static IPropertyMapper<IElement, IElementHandler> ElementMapper = new PropertyMapper<IElement, IElementHandler>()
88
{
@@ -15,6 +15,9 @@ public abstract partial class ElementHandler : IElementHandler
1515
internal readonly IPropertyMapper _defaultMapper;
1616
internal readonly CommandMapper? _commandMapper;
1717
internal IPropertyMapper _mapper;
18+
ElementHandlerState _handlerState;
19+
20+
ElementHandlerState IElementHandlerStateExhibitor.State => _handlerState;
1821

1922
protected ElementHandler(IPropertyMapper mapper, CommandMapper? commandMapper = null)
2023
{
@@ -40,24 +43,38 @@ public virtual void SetVirtualView(IElement view)
4043
_ = view ?? throw new ArgumentNullException(nameof(view));
4144

4245
if (VirtualView == view)
46+
{
4347
return;
48+
}
4449

4550
var oldVirtualView = VirtualView;
4651

4752
bool setupPlatformView = oldVirtualView == null;
4853

4954
VirtualView = view;
50-
PlatformView ??= CreatePlatformElement();
55+
if (PlatformView is null)
56+
{
57+
_handlerState = ElementHandlerState.Connecting;
58+
PlatformView = CreatePlatformElement();
59+
}
60+
else
61+
{
62+
_handlerState = ElementHandlerState.Reconnecting;
63+
}
5164

5265
if (VirtualView.Handler != this)
66+
{
5367
VirtualView.Handler = this;
68+
}
5469

5570
// We set the previous virtual view to null after setting it on the incoming virtual view.
5671
// This makes it easier for the incoming virtual view to have influence
5772
// on how the exchange of handlers happens.
5873
// We will just set the handler to null ourselves as a last resort cleanup
5974
if (oldVirtualView?.Handler != null)
75+
{
6076
oldVirtualView.Handler = null;
77+
}
6178

6279
if (setupPlatformView)
6380
{
@@ -77,6 +94,8 @@ public virtual void SetVirtualView(IElement view)
7794
}
7895

7996
_mapper.UpdateProperties(this, VirtualView);
97+
98+
_handlerState = ElementHandlerState.Connected;
8099
}
81100

82101
public virtual void UpdateValue(string property)
@@ -129,6 +148,8 @@ void IElementHandler.DisconnectHandler()
129148
PlatformView = null;
130149
DisconnectHandler(oldPlatformView);
131150
}
151+
152+
_handlerState = ElementHandlerState.Disconnected;
132153
}
133154
}
134155
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
3+
namespace Microsoft.Maui
4+
{
5+
/// <summary>
6+
/// Exposes the state of an element handler.
7+
/// </summary>
8+
[Flags]
9+
internal enum ElementHandlerState : byte
10+
{
11+
/// <summary>
12+
/// The handler is not connected to an element.
13+
/// </summary>
14+
Disconnected = 0x0,
15+
/// <summary>
16+
/// The handler is mapping all properties to the element.
17+
/// </summary>
18+
MappingProperties = 0x1,
19+
/// <summary>
20+
/// The handler is connecting for the first time to the element and mapping all properties.
21+
/// </summary>
22+
Connecting = MappingProperties | 0x2,
23+
/// <summary>
24+
/// The connected handler is now connecting to a new element and updating properties.
25+
/// </summary>
26+
Reconnecting = MappingProperties | 0x4,
27+
/// <summary>
28+
/// The handler is connected to an element.
29+
/// </summary>
30+
Connected = 0x8
31+
}
32+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace Microsoft.Maui
2+
{
3+
/// <summary>
4+
/// Exposes the state of an element handler.
5+
/// </summary>
6+
/// <remarks>
7+
/// To be migrated to a public API.
8+
/// </remarks>
9+
internal interface IElementHandlerStateExhibitor
10+
{
11+
/// <summary>
12+
/// Gets the state of the element handler.
13+
/// </summary>
14+
ElementHandlerState State { get; }
15+
}
16+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
4+
namespace Microsoft.Maui
5+
{
6+
internal static class InternalElementHandlerExtensions
7+
{
8+
/// <summary>
9+
/// The handler is connecting for the first time to the element and mapping all properties.
10+
/// </summary>
11+
/// <param name="handler"></param>
12+
/// <returns></returns>
13+
internal static bool IsMappingProperties(this IElementHandler handler) =>
14+
(handler as IElementHandlerStateExhibitor)?.State.HasFlag(ElementHandlerState.MappingProperties) ?? false;
15+
16+
/// <summary>
17+
/// Indicates whether the handler is connecting for the first time to the element and mapping all properties.
18+
/// </summary>
19+
/// <param name="handler"></param>
20+
/// <returns></returns>
21+
internal static bool IsConnectingHandler(this IElementHandler handler) =>
22+
(handler as IElementHandlerStateExhibitor)?.State.HasFlag(ElementHandlerState.Connecting) ?? false;
23+
24+
/// <summary>
25+
/// Indicates whether the connected handler is now connecting to a new element and updating properties.
26+
/// </summary>
27+
/// <param name="handler"></param>
28+
/// <returns></returns>
29+
internal static bool IsReconnectingHandler(this IElementHandler handler) =>
30+
(handler as IElementHandlerStateExhibitor)?.State.HasFlag(ElementHandlerState.Reconnecting) ?? false;
31+
}
32+
}

src/Core/src/Handlers/View/ViewHandler.Windows.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ public static void MapContextFlyout(IViewHandler handler, IView view)
112112
{
113113
if (view is IContextFlyoutElement contextFlyoutContainer)
114114
{
115+
if (handler.IsConnectingHandler() && contextFlyoutContainer.ContextFlyout is null) return;
116+
115117
MapContextFlyout(handler, contextFlyoutContainer);
116118
}
117119
}

0 commit comments

Comments
 (0)