* ๐ '''Deploy a new Default folder''' every time you update your client version, to ensure that the latest UI version is the foundation for your customizing.
* ๐ '''Only include xamls that are needed for your customizing.'''
** Remove files for child Areas and Items that are not included in this the projectthis customizing will be used for. This is especially relevant when copying customizings from other projects.<br>
=== How to select the right Control ===
** For example, there is no need to use a Filter + ListView to show a single UBIK object or property. Instead, you can bind the specific context of that object or property to a xaml control, and everything nested inside will inherit that binding context. This will be explained more in the section on [[XAML_Best_practices#Reusable_Templates|Reusable Templates]].
** Similarly, simple EvalExpressions can in many cases be replaced with [[XAML_Best_practices#Converters|Converters]].
** The Visibility attribute can be added to any control. '''There is no need to wrap any control in a Grid simply to apply a Visibility. ''' The same goes for layouting attributes such as Grid.Row/Column.
* ๐ When you need to show a collection of items such as ListView, '''always use our custom versions'''. These are UBIK-optimized for speed and performance.
** These are [[XAML_Tips#Version_3.7_.26_later|SelectionBoundListView]] on UWP and [[Xamarin_XAML#SfListViewExt|SfListViewExt]] on Xamarin.
** This is especially an issue in Xamarin, both for performance, but also because sfListViewExt tends to cause layouting issues by taking up more space than needed, unlike in UWP where a ListViewExt is capable of calculating its size based on the size of its items. Therefore, when using nested ListViews in Xamarin, constrain the size of the inner ListView with a fixed HeightRequest attribute (or WidthRequest in the case of a horizontal list).
** ๐ '''Alternatives to the optimized ListViews should be used with extreme caution.''' Controls such as CollectionView or BindableLayout are not optimized for good performance in UBIK.
<br><br>
=== Using Styles and Templates ===
** If the repeated customizing is used in only one xaml, create a ResourceDictionary on the parent container and defining your style there.
** Otherwise, place your style in UBIKThemes so it can be accessed across the entire project.
** '''For more information, read the section on [[XAML_Best_practices#Implicit_and_Explicit_Styling|Implicit and Explicit Styling]] below.'''
* ๐ If you repeatedly define the same combinations of controls, '''use Control/DataTemplates'''.
** DataTemplates and ControlTemplates are reusable XAML elements that can be defined once and applied several times throughout the customizing.
** You may have noticed that a DataTemplate is the basis for an item template in UBIKThemes. However, these can be applied anywhere in the xaml, and do not require a ListView to be rendered.
** '''For more information, read the section on [[XAML_Best_practices#Templating|Content Templating]] below.'''
* ๐ '''Reduce the number of elements, especially containers''', wherever possible.
** Layouts are often defined in multiple nested containers, usually Grids and StackPanels. This has an impact on performance if it leads to a very deep hierarchy of rendered elements. On mobile devices with less computational power, the difference can be felt.
** Sometimes itโs unavoidable that multiple containers are needed. In Xamarin, applying the [[Xamarin_XAML#Layout_compression_examples|HeadlessLayout]] style can reduce their impact on the visual tree.
** Some ideas for reducing the number of nested controls can be seen [[XAML_Best_practices#Alternatives_to_using_Multiple_Controls|later in this article]].
<br>
==== Implicit and Explicit Styling ====
* The localized Style definitions in this StackPanel will be passed down to all controls contained within it, no matter how deep the nesting goes.
* The BasedOn attribute can be used to create a sub-style based on another existing style. However, the TargetType must always match.
=== Simplifying Layouts ===In UWP / on desktop UBIK, the processor is generally powerful enough to handle more complex UIs. However, mobile devices running Xamarin versions of UBIK will noticeably struggle to render sophisticated UIs made of deeply nested levels of containers. There are two ways this situation can be improved; the first is to reduce the number of containers used, and the second is to apply [[Xamarin_XAML#Layout_compression_examples|Layout Compression]] wherever possible. Finally, some ideas will be presented for other ways to reduce the number of controls needed to render the same UI. ==== Reducing Containers ====Containers refers to controls whose purpose is to display other controls. The most basic examples are the Grid and StackLayout. These containers are frequently nested in order to finetune a UI, however, the downside is that each one adds a new branch in what is called a "visual tree', even if the control itself is not visible. When using many containers, it is useful to ask yourself if each container is really necessary, or if the visual tree can be simplified. The examples below show three different ways for showing the same content, each utilizing less controls, leading to a simpler visual tree. <brtabs><tab name="2 StackLayouts, 3 Labels"><source lang = "xml"><StackLayout> <StackLayout Orientation="Horizontal"> <Label Text="{x:Static resources:UBIKIcons.IconName}" FontFamily="{StaticResource UBIKSymbols}"/> <Label Text="Name" /> </StackLayout> <Label Text="Description" /></StackLayout></source></tab> <tab name="1 Grid, 3 Labels"><source lang = "xml"> <Grid Grid.ColumnDefinitions="24,*" Grid.RowDefinitions="Auto,Auto"> <Label Text="{x:Static resources:UBIKIcons.IconName}" FontFamily="{StaticResource UBIKSymbols}"/> <Label Grid.Column="1" Text="Name" /> <Label Grid.Row="1" Grid.ColumnSpan="2" Text="Description lorem ipsum..." /></Grid></source></tab> <tab name="1 Label"><source lang = "xml"><Label> <Label.FormattedString> <FormattedText> <Span FontFamily="{StaticResource UBIKSymbols}" Text="{x:Static resources:UBIKIcons.IconName}" /> <Span Text="Name & #10;" /> <Span Text="Description lorem ipsum..." /> </FormattedText> </Label.FormattedString></Label></source></tab> Note: & #10; (without the blank space) is the Xamarin glyph code for a newline. The equivalent in UWP is & #x0a;.</tabs> Now imagine the UI element should have a colored background. You may be tempted to wrap everything in a Frame, however, you can just as easily assign color using the Background attribute on the StackLayout, Grid, or even the Label itself. Granted, this example is very simple, however, the point illustrated here is that you should fid creative ways to reduce the number of controls nested in your UI. Another thing to consider is how many times this particular UI definition will be rendered on screen. You have more freedom to be uneconomical in your use of controls when when designing items that will appear once on a page, such as the page header, rather than with item templates or control templates that are rendered several, or even dozens, of times in one view. ==== Layout Compression ==== ==== Alternatives to using Multiple Controls ====
=== Template Selectors ===
Various parts of the UBIK UI are dynamically swapped in based on specific conditions. One example is the UBIKPropertyDirectItemContainer.xaml, which serves as the base for an item in the property list, and which renders a different type-appropriate editing UI for each kind of property input (such as textboxTextBox for manual input String, Double, or Integer; selectionfor link properties, or list-based String, Double, or Integer; clock and calendar pickers for DateTime; Lat., datetimeLon., and Alt. input for geo coordinates, etc).
The logical tree used by these selectors to render different UIs is documented in our article [[UBIK_Templates]].
<br><br>
=== DataTemplate vs. ControlTemplate in Xamarin ===
There are two main types of templates that can be used in UBIK to define reusable clusters of controls. Ignoring the technical differences, the functional differences boil down to;
==== DataTemplate ====
* Example 2: Consider a Property ItemTemplate, where we can view or edit a metaproperty. In this case, the '''context''' of the ItemTemplate would be a single property, and the bindings available would reflect that; we can bind to its Description, Value, DisplayString, Unit, or even its SortedValueRecords, if property change history is activated.
* Use a '''ContentControl''' or our custom '''controls:ContentControl''' (with the attribute ContentTemplate="{DynamicResource ...}" and TemplateContext="{Binding ...}") to display it.
<br>
==== ControlTemplate ====
ControlTemplate is technically used for showing how a specific control can be used; for example, if you want to customize a new template for how a Button should appear. However, it can be used similar to the DataTemplate, with one added bonus; its ContentPresenter sub-control allows for dynamically adding content at every instance, as opposed to a single universal layout that is shared by all.
* Note that implicit styles can also be added to the ControlTemplate, and will be inherited by any content nested in the ContentView.
* Use a '''ContentView''' (with the attribute ControlTemplate="{DynamicResource ...}") to display it.
<br>
{{Attention|Since the ControlTemplate is not technically designed to work directly with data bindings, it does inherit the context from its ContentView by default. However this can be easily fixed by adding the <nowiki>BindingContext="{TemplateBinding BindingContext}"</nowiki> attribute to the root grid of the template.}}
<br>
{{Hint|An understanding of '''Contexts''' is fundamental to using templates, as this informs what data bindings are directly available. Some more information can be found at this article on [[Object_hierarchy_in_XAML:_NextLevel,_ParentLevel,_LinkedLevel#The_ContentViewModel.28s.29|the ContentViewModel]] }}
[[Category:Pages with broken file links|XAML Best practices]]
[[Category:XAML|XAML Best practices]]
=== Context Switching ControlTemplate in UWP ===The situation is much simpler in UWP, which only makes use of the ControlTemplate to define custom templates. The ControlTemplate in UWP inherits the context from its content control, so no equivalent to Xamarin's <nowiki>BindingContext="{TemplateBinding BindingContext}"</nowiki> is required. The ContentControl is used to render an instance of a template.
=== Contexts and Context Switching ===
In xaml, every element in the UI is informed by a '''context'''. This is the data that is delivered by UBIK immediately when binding. Knowing the context that will be used by a content control is vital when using templates, as this directly affects what bindings you can prepare in your template. Furthermore, all content views that use the same template must have similar contexts, to a degree.
For example:
Two of the more frequently customized elements are Objects and their Metaproperties. A template used for a UBIK object will have bindings such as Title, Values[PROPERTY], etc, whereas one designed for a Metaproperty will have DisplayValue, Description, Unit, and so on. Using a template designed for a UBIK object will have no benefit if the context applied to it is that of a property, and vice versa.
==== Where does the context come from? ====
Context is inherited. When you begin customizing a xaml template, it generally has a known use, such as a child area, document viewer, or item in a property list, to name just a few of many. In these cases, the context is quite clear. However, when you begin creating general templates that can be used anywhere in the client, there will likely be the need to specify what context should be applied each time the template is used.
[[Image:XBP_ContentTemplates.png]]
In the above example, we see a variety of property editing fields. To cut down on repetitive XAMLing, a template is created for inputting a single property, consisting in this case of Description, DisplayValue, a placeholder label, and some indicators such as whether the property is required or filled. In each case, the context needs to be set to a specific metaproperty defined on the 'controls:ContentControl' that hosts each instance of the template, through the TemplateContext attribute.
<source lang = "xml">
<controls:ContentControl
ContentTemplate="{DynamicResource PropertyField_Required}"
TemplateContext="{Binding Properties.VisibleItems[MP_DETECTION]}" >
<controls:ContentControl.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Properties.VisibleItems[MP_DETECTION].PropertyClickedCommand}"/>
</controls:ContentControl.GestureRecognizers>
</controls:ContentControl>
</source>
{{Hint|Adding the behavior to the ContentControl, rather than defining it in the template itself, allows flexibility in the customizing as different property-editing commands can be paired with the same UI based on the required functionality.}}
==== Context Switching ====
To repeat, context is almost always inherited. If you forget to assign a specific context to a content control (as in the above example), the context of the XAML element that hosts that content control will be used. When you think about it, any number of nested Grids still inherit the context of the area or item template they are hosted in.
Context-switching is simply the name given to the act of assigning a different context to a particular control, when needed. It is also usually very simple to do:
'''UWP'''
<source lang = "xml">
DataContext="{Binding ...}"
</source>
<br>
'''Xamarin'''
<source lang = "xml">
BindingContext="{Binding ...}"
</source>
<br>
The above attributes can be added to any control to change it's binding context.
Try this experiment:
<source lang = "xml">
<TextBlock
DataContext="{Binding ParentLevel}"
Text="{Binding Title}" />
</source>
By using this code snippet, we expect to see the Title or the current object. However, because we have a context switch applied, we would instead see the Title of the parent object. For Xamarin use '''Label''' instead of TextBlock and '''BindingContext''' instead of DataContext.
{{Attention|Using this technique to switch the context of a control does it for ''all bindings on that control''. Since the entire control is now 'focused' directly on a different context, existing bindings will need to be adapted. An easy example is the Visibility of the TextBlock, which we might still want to bind to certain conditions on the child object, while displaying the data of the parent.
One exception is the controls:ContentControl, which through its TemplateContext attribute accepts the possibility to have a different context for its content, therefore decoupling the context of the template from the actual control, [[XAML_Best_practices#Context_Switching_And_Templates|as described below]].}}
Furthermore, since context continues to be inherited, any controls contained within the context-switched one (imagine it's a Grid containing more elements, rather than a simple TextBlock) will all also have the context of ParentLevel.
==== Context Switching And Templates ====
<tabs>
<tab name="DataTemplate (Xamarin only)">
As described in the previous section, DataTemplates are designed to be used as templates for data contexts, therefore the content control used to render them, controls:ContentControl, has the TemplateContext property which allows you to set the binding context '''for the template'''. The important difference to note is that the controls:ContentControl itself will not use the TemplateContext, but rather the inherited context from its hosting xaml.
Because they are independent of each other, it allows more sophisticated usage of binding contexts, for example, when ''Object A'' has ''Status B'', show ''Property C''.
<source lang = "xml">
Xamarin:
<controls:ContentControl (displayed on child area of Object A)
IsVisible="{Binding Values[STATUS], Converter={StaticResource EqualityToBool}, ConverterParameter=B}"
TemplateContext="{Binding PropertyItems[PROPERTYC]}"
ContentTemplate="{StaticResource MyPropertyTemplate}" />
</source>
</tab>
<tab name="ControlTemplate (Xamarin)">
On the other hand, since the ControlTemplate is not designed to be used this way, it has no inherent binding context attribute that can be assigned to it's content only. To use it this way would therefore require a context switch on the ContentView used to render it, with the related adjustments required to bindings placed on the ContentView itself;
<source lang = "xml">
Xamarin:
<ContentView (displayed on child area of Object A)
BindingContext="{Binding PropertyItems[PROPERTYC]}"
IsVisible="{Binding CallingViewModel.Values[STATUS], Converter={StaticResource EqualityToBool}, ConverterParameter=B}"
ControlTemplate="{StaticResource MyOtherPropertyTemplate}" />
</source>
{{Hint|CallingViewModel (as used on the IsVisible attribute) can be added to a metaproperty's binding path to bind to its context object.}}
</tab>
<tab name="ControlTemplate (Xamarin)">
No example yet.
</tab>
</tabs>
{{Attention|Remember that Styling in Xaml is type-based, so you cannot use the same template with controls:ContentControl (ContentTemplate attribute) and ContentView (ControlTemplate attribute), as DataTemplate and ControlTemplate are technically different types.}}
{{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]]