Changes

XAML Best practices

5,506 bytes added, 24 March
/* Improving performance on complex List item templates */
==== Alternatives to using Multiple Controls ====
[[Category:Pages with broken file links|XAML Best practices]][[Category:XAML|XAML Best practices]]
== Templating ==
{{UnderConstructionEnd}}
[[Category:Pages with broken file links|XAML Best practices]][[Category:XAML|XAML Best practices]]
== Performance ==
== Testing of UI ==
XAML can be sometimes very weird, there are dependencies or default values that you don’t see immediately. So, a good way to prevent millions of fixes for the customer, because the environment, different device or even a different windows version destroys your UI, is to write a test plan where you test your implementation. It’s important to see exactly your controls in action on their own and acting with each other, so you can prevent doing lots of ‘easy’ fixes.
 
{{UnderConstructionStart}}
 
== Improving performance on complex List item templates ==
 
=== Overview ===
Performance issues in XAML-based UI development often stem from unnecessary UI rendering and binding errors. Hidden elements remain in the UI tree, impacting performance, while premature bindings cause background errors. To optimize complex list item templates, UI content can be loaded only when needed, and binding errors can be reduced by applying view models at the control level. These improvements enhance efficiency, reduce log clutter, and improve maintainability.
 
=== Technique 1: Loading UI content on demand ===
It was discovered that UI controls hidden with '''IsVisible=False''' remain in the UI tree. To improve performance on highly complex item templates, like UBIKTaskItem, rendered repeatedly such as in ListViews, a workaround can be applied to only load the UI content when the '''visibility''' binding condition is met.
 
==== Previous Approach ====
Previously, we used '''IsVisible''' directly with a binding condition. The approach looked like this:
 
<source lang = "xml">
<Label IsVisible="{Binding MROViewModel.PreviousValue, Converter={StaticResource NullToNotBool}}">
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding MROViewModel.PreviousValue}" />
<Span Text=" " />
<Span Text="{Binding MROViewModel.Unit}" />
</FormattedString>
</Label.FormattedText>
</Label>
</source>
<br>
 
==== Improved Approach ====
To prevent unnecessary loading of UI elements when their '''visibility''' is False, it is possible to replace the UI content with a content hosting control, such as a '''ContentView''' or '''ContentControl'''. The original content should instead be defined as a template in '''UBIKThemes''', as shown below.
 
<source lang = "xml">
<ContentView>
<ContentView.Triggers>
<DataTrigger Binding="{Binding MROViewModel.PreviousValue, Converter={StaticResource NullToNotBool}, TargetNullValue=false, FallbackValue=false}"
Value="True" TargetType="ContentView">
<Setter Property="ControlTemplate" Value="{StaticResource PreviousValueTemplate}" />
</DataTrigger>
</ContentView.Triggers>
</ContentView>
</source>
<br>
 
The important part of the snippet above is the '''DataTrigger'''. Through this technique, the '''ControlTemplate''' of the content hosting control is only set once the visibility condition is met, preventing the UI content from being loaded until it is explicitly required.
And the associated '''ControlTemplate''', located in UBIKThemes:
<br>
<source lang = "xml">
<ControlTemplate x:Key="PreviousValueTemplate">
<Label>
<Label.FormattedText>
<FormattedString>
<Span Text="{TemplateBinding BindingContext.MROViewModel.PreviousValue}" />
<Span Text=" " />
<Span Text="{TemplateBinding BindingContext.MROViewModel.Unit}" />
</FormattedString>
</Label.FormattedText>
</Label>
</ControlTemplate>
</source>
<br>
 
'''Why This Change?'''
* '''More Modular''': The separation into discrete templates makes individual UI elements reusable and maintainable.
* '''Better Performance''': Eliminates unnecessary loading of UI elements in the background, that are not visible to the user.
 
<br>
 
 
 
 
=== Technique 2: Reducing background Binding errors ===
 
Complex item templates such as UBIKTaskItem were found to produce large numbers of '''errors''' while rendering, likely as bindings are being resolved before the relevant '''viewmodels''' can be loaded by the client. While these '''errors''' are temporary and not visible to the user, the cumulative effect of numerous binding errors raised while rendering items can be felt when navigating to pages with large numbers of items.
<br>
{{Attention|Unfortunately, these bindings errors are not normally logged in the UBIKDebug.log. Therefore, the recommendation is to use the following technique whenever using a ContentControl or controls:ContentControl.}}
 
==== Previous Approach ====
Initially, we used a '''ContentControl''' with a direct '''ContentTemplate''' and '''TemplateContext''', as shown below:
 
<tabs>
<tab name="Xamarin">
<source lang = "xml">
xmlns:ctrls="clr-namespace:UBIK.CPL.Controls;assembly=UBIK.CPL"
</source>
</tab>
<tab name="MAUI">
<source lang = "xml">
xmlns:ctrls="clr-namespace:UBIK.MAUI.Controls;assembly=UBIK.MAUI"
</source>
</tab>
</tabs>
 
<source lang = "xml">
<ctrls:ContentControl
ContentTemplate="{StaticResource TaskPropertyTemplateSelector}"
TemplateContext="{Binding MROViewModel}" />
</source>
<br>
 
[[File:Binding_logs.png]]
 
 
==== Improved Approach ====
One workaround that reduced the number of '''binding errors''' encountered was to refer to '''viewmodels''' indirectly in the bindings.
 
<source lang = "xml">
<ctrls:ContentControl x:Name="TaskPropertyTempSelCtrl"
BindingContext="{Binding MROViewModel}"
TemplateContext="{Binding BindingContext, Source={x:Reference TaskPropertyTempSelCtrl}}">
</ctrls:ContentControl>
</source>
<br>
 
The previous example used an '''MROViewModel''' binding directly in the '''TemplateContext''' property of the '''<ctrls:ContentControl>.'''
However, a workaround that seems to avoid triggering background binding errors is to apply the '''MROViewModel''' to the '''<ctrls:ContentControl>''' itself via the '''BindingContext''' property, and then request that '''BindingContext''' using the x:Reference syntax seen in the '''TemplateContext''' property.
 
'''Why This Change?'''
* '''Avoids Additional Binding Errors''': Using this workaround seems to prevent binding errors.
 
 
{{UnderConstructionEnd}}
[[Category:Pages with broken file links|XAML Best practices]]
[[Category:XAML|XAML Best practices]]
117
edits

Help improve this page!