Jump to: navigation, search

Difference between revisions of "XAML"


(Advanced)
(Differences between Mobile and UWP)
 
(104 intermediate revisions by 8 users not shown)
Line 1: Line 1:
The WinX User Interface can be vastly customized using XAML.
+
The WinX User Interface can be vastly customized using XAML. Starting with Version 3.2, this customizing experience can be largely controlled with the new [[Developer Mode]].
  
 
== Templates ==
 
== Templates ==
The UI is controlled by several predefined XAML templates which are loaded into the App at startup. There is a set of default template deployed with the App at installation, however, each of them can be overridden by placing the respective file in the folder [AppInstallPath\LocalState\XAML
+
The UI is controlled by several predefined XAML templates which are loaded into the App at startup. There is a set of default template deployed with the App at installation, however, each of them can be overridden by placing the respective file in the folder [AppInstallPath]\''LocalState\XAML''
 +
For further information see ''[[ UBIK Templates]]''.
  
 
=== General ===
 
=== General ===
* UBIKThemes.xaml
+
* [[UBIKThemes.xaml]]
 
Controls the overall styling and behavior of the App, like standard Brushes (Colors) and Fonts.
 
Controls the overall styling and behavior of the App, like standard Brushes (Colors) and Fonts.
  
 
==== AuthenticationPage ====
 
==== AuthenticationPage ====
* UBIKSplashArea.xaml
+
[[File:AuthenticationPage.PNG|thumb|AuthenticationPage]]
* UBIKPageNavigation.xaml
+
* [[UBIKSplashArea.xaml]]
 +
* UBIKPageNavigation.xaml -> Deprecated and changed to UBIKHomePageButtons.xaml {{Version/WinXSince|3.0.0}}
 +
* UBIKProfileItem.xaml
 +
{{clear}}
 +
 
  
 
=== Content Pages ===
 
=== Content Pages ===
Line 18: Line 23:
  
 
==== RootPage ====
 
==== RootPage ====
 +
[[File:MainPage.PNG|thumb|RootPage]]
 
* UBIKMainLeftArea.xaml
 
* UBIKMainLeftArea.xaml
 
* UBIKMainItem.xaml
 
* UBIKMainItem.xaml
 
* UBIKMainItemSmall.xaml
 
* UBIKMainItemSmall.xaml
 +
{{clear}}
 +
  
 
==== ChildPage ====
 
==== ChildPage ====
 +
[[File:ChildPageNew.PNG|thumb|ChildPage]]
 
* UBIKChildItem.xaml
 
* UBIKChildItem.xaml
 
* UBIKChildItemSmall.xaml
 
* UBIKChildItemSmall.xaml
 +
* UBIKChildArea.xaml
 +
* UBIKChildAreaSmall.xaml
 
* UBIKChildAction.xaml
 
* UBIKChildAction.xaml
 
* UBIKPriorityPropertyItem.xaml
 
* UBIKPriorityPropertyItem.xaml
 +
{{clear}}
 +
  
 
==== DetailsPage ====
 
==== DetailsPage ====
Line 32: Line 45:
 
* UBIKDocumentItemSmall.xaml
 
* UBIKDocumentItemSmall.xaml
  
 +
 +
== Specific {{UBIK}} Controls ==
 +
=== Basic ===
 +
==== CoolGridSplitter (UBIK.WinX.Controls) ====
 +
Allows to make rows or columns of a grid user-resizable
 +
 +
Example:
 +
<source lang = "xml">
 +
<uc:CoolGridSplitter
 +
    x:Name="ChildAreaGridSplitter"
 +
    Height="10"
 +
    HorizontalAlignment="Center" VerticalAlignment="Bottom"
 +
    Background="Transparent"
 +
    Foreground="White"
 +
    ResizeBehavior="CurrentAndNext" ResizeDirection2="Rows"/>
 +
</source>
 +
 +
==== UBIKImageEditor ====
 +
<tabs>
 +
<tab name="UWP">
 +
It's essentially the [https://help.syncfusion.com/uwp/image-editor/overview SfImageEditor] from Syncfusion. Theoretically, customizability mentioned in their official documentations should be supported in {{UBIK}} out of the box.
 +
One example is to customize the visibility of the toolbar of such an image editor. The following example hides the toolbar.
 +
<source lang = "xml">
 +
xmlns:ctrls="using:UBIK.WinX.UI.Controls"
 +
<ctrls:UBIKImageEditor ...
 +
    xmlns:sfImageEditor="using:Syncfusion.UI.Xaml.ImageEditor">
 +
    <sfImageEditor:SfImageEditor.ToolbarSettings>
 +
<sfImageEditor:ToolbarSettings IsToolbarVisiblity="False"/>
 +
    </sfImageEditor:SfImageEditor.ToolbarSettings>
 +
</ctrls:UBIKImageEditor>
 +
</source>
 +
</tab>
 +
 +
<tab name="Mobile(Xamarin)">
 +
It's essentially the [https://help.syncfusion.com/xamarin/image-editor/overview SfImageEditor] from Syncfusion. Theoretically, customizability mentioned in their official documentations should be supported in {{UBIK}} out of the box.
 +
One example is to customize the visibility of the toolbar of such an image editor. The following example hides the toolbar.
 +
<source lang = "xml">
 +
xmlns:ctrls="clr-namespace:UBIK.CPL.Controls;assembly=UBIK.CPL"
 +
<ctrls:UBIKImageEditor ...
 +
    xmlns:sfImageEditor="clr-namespace:Syncfusion.SfImageEditor.XForms;assembly=Syncfusion.SfImageEditor.XForms">
 +
    <sfImageEditor:SfImageEditor.ToolbarSettings>
 +
<sfImageEditor:ToolbarSettings IsVisible="false" />
 +
    </sfImageEditor:SfImageEditor.ToolbarSettings>
 +
</ctrls:UBIKImageEditor>
 +
</source>
 +
</tab>
 +
</tabs>
 +
 +
The MergeAnnotationsOnSave property allows to configure whether annotations should be shared through the {{UBIK}} property from the respective Annotation classification (''false''), or if they should be merged directly into the original file (''true'', this is the default option): {{Version/WinXSince|3.8.0}} {{Version/XamarinSince|1.2.0}}
 +
<source lang = "xml">
 +
<ctrls:UBIKImageEditor MergeAnnotationsOnSave="true" <!--true to merge automatically, false to use the classification-->
 +
  ...
 +
</ctrls:UBIKImageEditor>
 +
</source>
 +
 +
 +
 +
 +
==== UBIKPdfViewer ====
 +
<tabs>
 +
<tab name="UWP">
 +
* The Top-Toolbar can be customized by setting: UBIKAppBarBackgroundThemeBrush
 +
* The Annotation-Toolbar can be customized by setting: UBIKPdfAnnotationToolbarBackgroundThemeBrush
 +
* The color of the buttons in the toolbar is defined by: UBIKAppBarButtonForegroundThemeBrush
 +
* The Save button can be hidden with SaveButtonVisibility="Collapsed"
 +
* The Annotation button can be hidden with AnnotationButtonVisibility="Collapsed"
 +
* The HS button can be hidden with HotspotButtonVisibility="Collapsed"
 +
* The undo and redo operations can be turned on/off with IsUndoEnabled="true/false". The default value is false. When turned off, the two relevant buttons will be hidden in the toolbar. {{Version/WinXSince|4.4}}
 +
 +
{{Attention|Please be careful when you enable undo and redo. Because {{key press|Ctrl}} + {{key press|Z}} (or whichever other combination in your keyboard layout) is the shortcut to trigger an undo. Therefore, it's possible that you accidentally undo/revert your changes in the PDF viewer when you are typing.}}
 +
 +
* The default stroke width for Annotations can be defined with the AnnotationDefaultStrokeWidth property in the UBIKThemes.xaml:
 +
<source lang = "xml">
 +
<x:Double x:Key="AnnotationDefaultStrokeWidth">1</x:Double>
 +
</source>
 +
</tab>
 +
 +
<tab name="Mobile(Xamarin)">
 +
On a Xamarin UBIKPdfViewer instance (e.g. in the UBIKDocumentContentArea template), you can configure its EnableSeparateInkStrokes value.
 +
* True (default): Every ink stroke has its own session. You can select it and change its color/thickness/transparency/etc. separately from others.
 +
* False: If you do not end the session explicitly by exiting the ink mode, all strokes belong in the same session. And they can only be interacted with as a whole.
 +
<source lang = "xml">
 +
xmlns:ctrls="clr-namespace:UBIK.CPL.Controls;assembly=UBIK.CPL"
 +
<ctrls:UBIKPdfViewer
 +
    ...
 +
    EnableSeparateInkStrokes="True" />
 +
</source>
 +
</tab>
 +
 +
</tabs>
 +
 +
 +
 +
 +
=== Advanced ===
 +
==== [[EvalExpression]] ====
 +
Allows to evaluate a C# expression in XAML, using any amount of [[EvalExpression#Parameters|EvalExpressionParameters]]
  
  
  
== Specific {{UBIK}} Elements ==
 
  
 
== Converters ==
 
== Converters ==
=== Basic ===
+
These are classes in our code used to convert one form of data into another (For example: string to color, bool to string, color to string…). We are using it often on Data Bindings, so we can simply ‘change’ the data that got provided by the model. Mostly, in our environment, we use the Converters for the Visibility Property, Background Property or the Source Property (converting Byte to an Image).
* BooleanToVisibilityConverter
+
 
Converts a Boolean into a Visibility, where ''true'' will result in ''Visibility.Visible''.
+
Initialization of a converter in a XAML file:
* BooleanToCollapsedConverter
+
<source lang = "xml"> <converters:ItemCountLesserThanToVisibilityConverter
Converts a Boolean into a Visibility, where ''true'' will result in ''Visibility.Collapsed''.
+
x:Key="ItemCountLesserThanToColConverter"
 +
EqualOrBiggerThan="Visible"
 +
LesserThan="Collapsed" />
 +
<!-- This Converter example specifically counts the items that will go into a container (ListView etc..) and gets a parameter passed when it should be a certain visibility. Next example shows you how to configure your converter.-->     
 +
</source>
 +
<br>
 +
Using the ItemCountLesserThanToVisiblity in a visibility attribute:
 +
<source lang = "xml"> <Visibility="{Binding Source={StaticResource RootListFilter}, Path=Count, Converter={StaticResource ItemCountLesserThanToColConverter }, ConverterParameter=13, FallbackValue=Collapsed}"/>
 +
<!--In this case is the parameter 13, so when it gets passed the Count gets checked e.g. how many items there are and when it’s under 13 it will collapse. -->     
 +
</source>
 +
<br>
 +
Example of an EqualToVisConverter being used in order to set the visibility of a grid:
 +
<source lang = "xml"> <Grid Visibility="{Binding Values [MP_SCOPECHANGE], Converter={StaticResource EqualToVisConverter}, ConverterParameter=30}">
 +
</Grid>
 +
<!--The grid will be ONLY visible if the value of this MetaProperty equals the value of the converter parameter. -->     
 +
</source>
 +
<br>
 +
Example of a StringFormatConverter, which converts a value into a string and also accepts a parameter, in this case the GlobalDateTimeFormat, which ‘tells’ the converter how to format the string:
 +
<source lang = "xml"> <TextBlock Grid.Row="1" Text="{Binding Values [MP_LATE_START_MATAP], Converter={StaticResource StringFormatConverter}, ConverterParameter={StaticResource GlobalDateTimeFormat} }"/>
 +
</source>
 +
 
 +
=== List of all converters ===
 +
For a complete and up-to-date list of all converters, please refer to the [[Developer_Mode#Browsing_the_ViewModel.2FContext|developer mode]].
 +
 
 +
 
  
 
=== Advanced ===
 
=== Advanced ===
Line 50: Line 183:
 
Example:
 
Example:
 
<source lang = "xml">
 
<source lang = "xml">
 +
    <StackPanel Orientation="Horizontal">
 +
        <StackPanel.Resources>
 +
            <!--  Instantiate the converter and bind the the Param0 to a SearchBox on this page  -->
 +
            <converters:StringFormatConverter x:Key="URIConverter" Param0="{Binding ElementName=SkypeQuery, Path=QueryText}" />
 +
        </StackPanel.Resources>
 +
        <!--  Create a SearchBox that calls the typed Name via Skype on enter  -->
 +
        <SearchBox
 +
            x:Name="SkypeQuery"
 +
            Width="240" Height="40"
 +
            FontSize="18"
 +
            PlaceholderText="Call Skype">
 +
            <Interactivity:Interaction.Behaviors>
 +
                <Core:EventTriggerBehavior EventName="QuerySubmitted">
 +
                    <Core:InvokeCommandAction
 +
                          Command="{Binding NavigateToURICommand}"
 +
                          CommandParameter="{Binding ElementName=SkypeQuery, Path=QueryText, Converter={StaticResource URIConverter},
 +
                          ConverterParameter=skype\:\{0\}\?call }" />
 +
                </Core:EventTriggerBehavior>
 +
            </Interactivity:Interaction.Behaviors>
 +
        </SearchBox>
 +
    </StackPanel>
 +
</source>
 +
 +
 +
* [[EvalExpressionConverter]]
 +
Evaluates a C# expression with 3 optional variables (''Param0, Param1, Param2'') and returns the result.  The object fed into the converter can be referenced in the expression as ''Context''.
 +
 +
Example:
 +
<source lang = "xml">
 +
    <Grid>
 +
        <Grid.Resources>
 +
            <!--  Instantiate the converter and bind the Context to the current DataContext, the Param0 to a UI element of this page  -->
 +
            <converters:EvalExpressionConverter x:Key="CodeConverter" Context="{Binding}" Param0="{Binding ElementName=ChildListView, Path=Name}" />
 +
        </Grid.Resources>
 
         <StackPanel Orientation="Horizontal">
 
         <StackPanel Orientation="Horizontal">
            <StackPanel.Resources>
+
             <!--  Create a TextBox where we can enter a C# expression -->
                <!--  Instantiate the converter and bind the the Param0 to a SearchBox on this page  -->
+
             <TextBox
                <converters:StringFormatConverter x:Key="URIConverter" Param0="{Binding ElementName=SkypeQuery, Path=QueryText}" />
+
                 x:Name="CodeQuery"
            </StackPanel.Resources>
+
                 MinWidth="240" Height="40"
             <!--  Create a SearchBox that calls the typed Name via Skype on enter  -->
+
             <SearchBox
+
                 x:Name="SkypeQuery"
+
                 Width="240" Height="40"
+
 
                 FontSize="18"
 
                 FontSize="18"
                 PlaceholderText="Call Skype">
+
                 PlaceholderText="Expression">
 +
            </TextBox>
 +
            <!--  Create a TextBlock where we display the result of the compiled expression -->
 +
            <TextBlock Text="{Binding ElementName=CodeQuery, Path=Text, Converter={StaticResource CodeConverter}}" />
 +
        </StackPanel>
 +
    </Grid>
 +
</source>
 +
 
 +
 
 +
* [[CollectionToViewConverter]]
 +
Outdated and replaced by the [[XAML_Changes_in_UBIK_WinX_3.5#Filtering_by_expressions|ListCollectionView]].
 +
 
 +
 
 +
* [[ChildItemTemplateSelectorSuffixConverter]]
 +
Converts a template selector to use templates with a certain suffix (e.g. "_Grid" to use "UBIKChildItem_Grid.xaml" instead of "UBIKChildItem.xaml"). The small template file name will be combined as <TemplateName><Suffix>Small.xaml (e.g. "UBIKChildItem_GridSmall.xaml").
 +
 
 +
Example:
 +
<source lang = "xml">
 +
    <Grid>
 +
        <Grid.Resources>
 +
            <!--  Instantiate the template selectors and bind them to the instance of the coverter  -->
 +
            <tpl:ChildItemTemplateSelector x:Key="ChildItemTemplateSelector" />
 +
            <tpl:ChildItemTemplateSmallSelector x:Key="ChildItemTemplateSmallSelector" />
 +
            <converters:ChildItemTemplateSelectorSuffixConverter x:Key="ChildItemTemplateSelectorSuffixConv" TemplateSelector="{Binding Source={StaticResource ChildItemTemplateSelector}}" TemplateSmallSelector="{Binding Source={StaticResource ChildItemTemplateSmallSelector}}"/>
 +
        </Grid.Resources>
 +
        <!-- The itemselector template binds to the suffix that should be used (in this case a binding to a stored profile parameter is used to switch the item template suffix between "_Grid" and "_List" -->
 +
 
 +
        <StackPanel>
 +
            <CheckBox Grid.Column="0">
 
                 <Interactivity:Interaction.Behaviors>
 
                 <Interactivity:Interaction.Behaviors>
                     <Core:EventTriggerBehavior EventName="QuerySubmitted">
+
                     <Core:EventTriggerBehavior EventName="Checked">
                         <Core:InvokeCommandAction
+
                        <!-- Store the Profile Variable "ChildItemsViewMode" to Grid or List - depending on the check state of the check box -->
                              Command="{Binding NavigateToURICommand}"
+
                         <Core:InvokeCommandAction Command="{Binding StoreProfileParameterCommand}" CommandParameter="ChildItemsViewMode=_Grid"/>
                              CommandParameter="{Binding ElementName=EcoQuery, Path=QueryText, Converter={StaticResource URIConverter},
+
                    </Core:EventTriggerBehavior>
                              ConverterParameter=skype:\{0\}\?call }" />
+
                    <Core:EventTriggerBehavior EventName="Unchecked">
 +
                        <Core:InvokeCommandAction Command="{Binding StoreProfileParameterCommand}" CommandParameter="ChildItemsViewMode=_List"/>
 
                     </Core:EventTriggerBehavior>
 
                     </Core:EventTriggerBehavior>
 
                 </Interactivity:Interaction.Behaviors>
 
                 </Interactivity:Interaction.Behaviors>
             </SearchBox>
+
             </CheckBox>
 +
            <ListView
 +
                    x:Name="ChildListView"
 +
                    HorizontalContentAlignment="Stretch"
 +
                    ItemTemplateSelector="{Binding Path=StoredProfileParameters[ChildItemsViewMode], Converter={StaticResource ChildItemTemplateSelectorSuffixConv}, ConverterParameter=Normal, FallbackValue=List}"
 +
                    ItemsPanel="{StaticResource ChildPageItemsPanelTemplate}"
 +
                    ItemsSource="{Binding Children.Items}"
 +
                    ScrollViewer.VerticalScrollBarVisibility="Auto" SelectionMode="None">
 +
                <ListView.ItemContainerStyle>
 +
                    <Style TargetType="ListViewItem">
 +
                        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
 +
                        <Setter Property="Padding" Value="0" />
 +
                        <Setter Property="Margin" Value="0,0,16,0" />
 +
                    </Style>
 +
                </ListView.ItemContainerStyle>
 +
                <ListView.ItemContainerTransitions>
 +
                    <TransitionCollection>
 +
                        <EntranceThemeTransition FromHorizontalOffset="400" />
 +
                    </TransitionCollection>
 +
                </ListView.ItemContainerTransitions>
 +
            </ListView>
 
         </StackPanel>
 
         </StackPanel>
 +
    </Grid>
 
</source>
 
</source>
  
* [[EvalExpressionConverter]]
 
Evaluates a C# expression with 3 optional variables (''Param0, Param1, Param2'') and returns the result.
 
  
Example:
+
 
<source lang = "xml">
+
 
            <Grid>
+
== Properties ==
                <Grid.Resources>
+
Working with Properties is a foundational role of the UI customizer. Be aware that the term can refer to various elements of a content object's datamodel, including details like its Title, SubTitle, UID, classification info, etc. However, this article deals specifically with '''content properties'''; those which are displayed under the Property tab in the UBIK client.
                    <!--  Instantiate the converter and bind the Context to the current DataContext, the Param0 to a UI element of this page  -->
+
 
                    <converters:EvalExpressionConverter x:Key="CodeConverter" Context="{Binding}" Param0="{Binding ElementName=ChildListView, Path=Name}" />
+
=== Displaying Properties ===
                </Grid.Resources>
+
Displaying with properties is an extremely common requirement in custom UIs. UBIK offers several different bindings, each with specific benefits. It may be enough to simply display the value of a simple string or numeric property somewhere in your UI, or else you might need to display complex properties or execute a certain property-based command.
                <StackPanel Orientation="Horizontal">
+
 
                    <!-- Create a TextBox where we can enter a C# expression  -->
+
The table below clarifies the various functionalities and how they can best be used in different scenarios.
                    <TextBox
+
 
                        x:Name="CodeQuery"
+
It is important to note that for these bindings we are assuming a content viewmodel (ie. an object observed in the client, either after navigating to it, or else when viewing it as an item in the child list of another content object).
                        MinWidth="240" Height="40"
+
 
                        Margin="0,10,10,0" HorizontalAlignment="Right"
+
{| class="wikitable"
                        VerticalAlignment="Top"
+
! Collection !! {{Tooltip|Performance|Could rendering be slowed down by using this binding, especially on ItemTemplates used in a list of many items.}} !! {{Tooltip|Capability|Extent of the viewmodel accessed}} !! {{Tooltip|Lazy-Loaded|Loaded on-demand (vs. always present)}}
                        FontSize="18"
+
|-
                        PlaceholderText="Expression">
+
| Values || Great || Very limited - Read only, Property value only || No
                    </TextBox>
+
|-
                    <!--  Create a TextBlock where we display the result of the compiled expression -->
+
| PropertyItems || Good || Limited - Read only || No
                    <TextBlock Text="{Binding ElementName=CodeQuery, Path=Text, Converter={StaticResource CodeConverter}}" />
+
|-
                </StackPanel>
+
| PropertyByName || Ok up to 5 uses || Unlimited - Full PropertyViewModel || Yes
            </Grid>
+
|-
 +
| Properties.XItems || Impacted || Unlimited - Full PropertyViewModel || Yes
 +
|-
 +
|}
 +
 
 +
==== Values[MP_PROPERTY] ====
 +
* This is the most basic and performant way to bind to a property value.
 +
* This collection simply displays the 'true' value of a property, meaning that it is only useful displaying for simple properties, such as String, Int, Dbl, unformatted DateTime, etc. Properties that have a DisplayValue that is different from their true value, such as GUIDs or selective list items with labels, are not best displayed using this binding.
 +
* For complex iproperties, it can be still be used in the xaml for non-display purposes, such as in combination with converters or commands. It is immediately present on the most basic content viewmodel (the ContentListItemViewModels used by child lists) without having to be loaded, and remains the best choice in most cases.
 +
 
 +
<tabs>
 +
<tab name="Don't Do">
 +
<source lang = "XML">
 +
Command="{Binding NavigateToGuidCommand}" Command Parameter="{Binding Properties.AllItems[MP_GUID].Value}"
 
</source>
 
</source>
 +
</tab>
 +
<tab name="Instead do">
 +
<source lang = "XML">
 +
Command="{Binding NavigateToGuidCommand}" Command Parameter="{Binding Values[MP_GUID]}"
 +
</source>
 +
</tab>
 +
</tabs>
 +
 +
==== PropertyItems[MP_PROPERTY]... ====
 +
This collection can be used when the Value collection does not suffice for displaying appropriate values. This PropertyViewModel presents more options than the simple Values collection, however, <u>it should still only be used for displaying text in the UI</u> as it bypasses the modern functionality offered by UBIK, such as user rights, locked states, etc.
 +
 +
==== Properties.XItems[MP_PROPERTY]... ====
 +
These collections were created as a response to the criticism that earlier collections like Values and PropertyItems did not expose enough of a content object's viewmodel to be useful to our ever more sophisticated custom UIs. These collections now provide the full PropertyViewModel, where all aspects of a property (including ''it's'' properties, such as Unit attached to Double, the seperate Min/Value/Max valueitems, Date and Time extracted from the DateTime property, Lon/Lat or Alt extracted from the Geo property, and many more) can be accessed in Bindings.
 +
* However, the downside of accessing this huge viewmodel is the noticeable performance impact, as it loads all instances of properties for the context object, even though only one (MP_PROPERTY) is requested. This impact is felt especially when such as binding is used on an item template in a list with many content objects, of which each has many properties.
 +
* These collections are [[Fast_Startup_(Client)|Lazy Loaded]]*, which means that they are not loaded by default, however, a single binding to that collection will load it. When used on an item template in a list, all viewmodels for all properties for all child items will simultaneously be loaded, leading to the performance impact described in this article.
 +
* "Properties.XItems" is not a real collection. The most frequently used collections are Properties.AllItems, Properties.VisibleItems, Properties.EditableItems, and Properties.ImportantItems (properties which fall into the [[UBIK_WinX_Client_Basics#High_priority_properties|Priority threshold]]). The number of properties delivered to a content object in each collection (for example; all, 80%, 40% and 10%, respectively) is also a consideration when estimating the performance impact of binding to these collections; simply put, use the smallest collection possible where the desired property is consistently located.
 +
 +
==== PropertyByName[MP_PROPERTY]... ====
 +
This collection was created to overcome the performance impact arising from using Properties.XItems, by individually loading the PropertyViewModel for the named property. However, note that the benefit only lasts while the binding is used sparingly; rendering performance will be roughly the same as loading the Properties collection after 3-5 uses on a single item template.
 +
 +
{{Hint|The Values[ ] collection delivers the property's value as a string. The equivalent for the other bindings (above shown as '...') is <code>{Binding Collection[PROPERTY_NAME].'''DisplayValue'''}</code>, however, the capability of these viewmodels goes far beyond the DisplayValue. Use [[Developer_Mode]] to learn more.}}
 +
 +
 +
==== * Troubleshooting null property values ====
 +
Because certain property collections are Lazy-loaded as described above, it may be the case that bindings to these properties appear null in certain circumstances, especially if the collection is loaded after the page is rendered, such as through a command or behavior. To troubleshoot this issue, you can ensure that the property collection is accessed during rendertime rather than runtime (simply put, while the page is being constructed rather than during normal use) by applying the same binding to, for example, a Label. This measure should still work if the Label is hidden from view using a visibility binding.
 +
 +
 +
 +
 +
=== Editing Properties ===
 +
There are currently 3 main ways to trigger property editing (aside from direct editing) in XAML:
 +
* [[EditPropertyValueCommand]] uses a MetaProperty name as a parameter, to trigger the editing dialogue for that metaproperty.
 +
** It is located on the ContentViewModel, and automatically triggers a Save and Commit once the edit is confirmed.
 +
* Similarly, the (PropertyViewModel).ShowEditorCommand/.PropertyClickedCommand triggers the editing dialogue, however, being located on the PropertyViewModel, it is necessary to first access a single property, such as by triggering the command on a list item template, or by directly binding to a specific one using a metaproperty indexer.
 +
** These two commands are equivalent, the ShowEditorCommand being more general and redirecting for Live Values or properties with Value Records, or else triggering the PropertyClickedCommand.
 +
** These commands can be seen in action as the standard UI for properties when clicking on the icon to trigger "indirect" editing for any individual metaproperty.
 +
** Property changes are not saved automatically, but set the ToSave flag on the ContentViewModel, meaning that a SaveAndCommit command is required to commit the changes.
 +
* The [[XAML_Tips#SetPropertyValueCommand|Set Property Value Command]] sets a named property to a specific or calculated (such as through an [[EvalExpression]]) value.
 +
  
  
== Behaviors ==
 
  
 
== Commands ==
 
== Commands ==
* [[NavigateToURICommand]]
+
{{Hint|The previously listed available commands for binding is removed from here. Since it's more accurate and up-to-date to use the [[Developer Mode]] to inspect them in your version of the clients.}}
 +
 
 +
=== Examples for commands with complex parameters ===
 +
 
 +
==== CaptureMediaCommand ====
 +
<tabs>
 +
<tab name="UWP">
 +
<source lang = "xml">
 +
<Button
 +
    ...
 +
    xmlns:controls="using:UBIK.WinX.Controls"
 +
    Command="{Binding CaptureMediaCommand}">
 +
    <Button.CommandParameter>
 +
        <controls:KeyValueList>
 +
            <controls:KeyValueParameter Key="MediaCaptureMode" Value="Video" />
 +
            <controls:KeyValueParameter Key="ChildMetaDefUid" Value="6170a068-2314-4444-ad62-0da99769a048" />
 +
        </controls:KeyValueList>
 +
    </Button.CommandParameter>
 +
</Button>
 +
</source>
 +
</tab>
 +
 
 +
<tab name="Mobile(Xamarin)">
 +
<source lang = "xml">
 +
<Button
 +
    ...
 +
    xmlns:classes="clr-namespace:UBIK.CPL.Classes;assembly=UBIK.CPL"
 +
    Command="{Binding CaptureMediaCommand}">
 +
    <Button.CommandParameter>
 +
        <classes:KeyValueList>
 +
            <classes:KeyValueParameter Key="MediaCaptureMode" Value="Video" />
 +
            <classes:KeyValueParameter Key="ChildMetaDefUid" Value="6170a068-2314-4444-ad62-0da99769a048" />
 +
        </classes:KeyValueList>
 +
    </Button.CommandParameter>
 +
</Button>
 +
</source>
 +
</tab>
 +
</tabs>
 +
 
 +
{{Hint|The KeyValueList parameter is supported only {{Version/WinXSince|3.8}}{{Version/XamarinSince|1.2}}. In previous versions, simple string parameters were supported.}}
 +
{{Attention|Whether the creation succeeds also depends on the server configuration. For example, if "*.mp4" is not included as a selective list item in the [[SYSCLS_FILEDOCUMENT|file type]] meta property, video document creation will not be possible. Similarly, audio document creation requires a file type "*.wav" to be included in the selective list.}}
 +
 
 +
* MediaCaptureMode: Photo, Video, Audio. Defaults to Photo if unspecified;
 +
* ChildMetaDefUid: The Guid of the child meta definition to be used for creating the captured media document. If unspecified, the client will simply pick the first child meta definition that is of media type and is allowed under the current context/parent object.
 +
 
 +
 
 +
 
 +
 
 +
== Object Filtering ==
 +
Filtering of objects is a common requirement in UBIK projects. The table below shows the three main approaches, with the functionality each offers.
 +
 
 +
{| class="wikitable"
 +
! Type !! Configuration/Requirements !! {{Tooltip|Persisted|Filter criteria are retained when navigating, or even closing the client.}}  !! {{Tooltip|Multiple/Complex Values|Multiple user inputs supported for a single filter property.}}  !! {{Tooltip|Property type|Data elements supported as filter properties.}} !! {{Tooltip|Possible Item Source|Collections supported as item sources.}}
 +
|-
 +
| Query || Fully defined on the server || Yes || Limited (DateTime, Dbl, Int) where a range is possible. || {{Tooltip|Content properties|The kind displayed in the Property tab of the UBIK client}} only || {{Tooltip|Content objects|The kind displayed in the Children tab of the UBIK client}}, Documents
 +
|-
 +
| Property-Based Content Filters || Defined in XAML, requires custom  [[SYSCLS_CHILDAREATEMPLATE|Child Area template name]] || Yes || No || {{Tooltip|Content properties|The kind displayed in the Property tab of the UBIK client}} only || {{Tooltip|Content objects|The kind displayed in the Children tab of the UBIK client}} only
 +
|-
 +
| Dynamic Filters || Fully defined in XAML || No || Yes || Any bindable data (eg. Content properties, metadefinitions, etc). || Content objects, Properties, Documents, etc
 +
|-
 +
|}
 +
 
 +
A [[Query]] is a container that delivers a defined collection of content objects. Properties can be added to the query to serve as filter criteria, where a user can perform their search by editing these properties.
 +
 
 +
[[Property_Based_Content_Filters]] are a xaml-based customization that connects a user input control (usually a textbox) with a specific content property on the content object. This user input is converted into filter criteria and applied directly to the child list, where only matched objects are retained.
 +
 
 +
[[HowTo:Implement_Custom_Filtering|Dynamic Filtering]] is the most flexible, but also the most complex, method of XAML-based filtering. A set of [[EvalExpression|EvalExpressions]] converts user inputs into a complex filter string, which is then applied immediately to whichever ItemsSource is defined in the [[XAML_Changes_in_UBIK_WinX_3.5#Filtering_by_expressions|ListCollectionView]]/[[Xamarin_XAML#FeatureRelated|SfDataSourceExt]]. Note that in this approach, user inputs are not directly connected to any data, which means that reloading the page in any way (eg. by navigation) causes the input controls to return to their xaml-defined state.
 +
 
 +
{{Attention|While any of the above approaches can be used, it is never recommended to mix approaches, as this causes multiple rounds of filtering per keystroke that will noticeably impact performance, especially when many objects and filters are involved!}}
 +
 
 +
 
 +
 
 +
 
 +
== Miscellaneous ==
 +
<br>
 +
 
 +
=== Behaviors in style definitions ===
 +
It's very common and easy to attach behaviors to different UI controls to extend their functionalities. For example, see [[#Advanced_2|StringFormatConverter]].
 +
 
 +
For better code reusability, it's sometimes necessary to implement the functionality of a control in a style so that it can be applied to the same control used in various occasions. In this case, the regular behaviors won't work and you have to use a special type AttachBehavior with some limitations. Below is such an example.
 +
 
 +
<tabs>
 +
<tab name="UWP">
 +
In this example, a style for the Grid control is defined with a behavior which executes the EditPropertyValueCommand upon tapped. There are two things to note here:
 +
* When attaching multiple behaviors to controls, you have to explicitly declare a BehaviorCollection and place all behaviors underneath. Unlike outside of style definitions, this is mandatory. Without it, only the last behavior will be effective.
 +
* Bindings work the same way in general. However, it's not possible to bind to named elements through the <code>"{Binding ElementName=someName, Path=..."</code> syntax and there doesn't seem to be a way to achieve similar goals.
 +
<source lang = "xml">
 +
xmlns:behaviors="using:UBIK.WinX.Behaviors"
 +
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
 +
<Style x:Key="UBIKNamePropertyGrid" TargetType="Grid">
 +
    <Setter Property="behaviors:AttachBehavior.Behaviors">
 +
        <Setter.Value>
 +
            <behaviors:BehaviorCollection>
 +
                <core:EventTriggerBehavior EventName="Tapped">
 +
                    <core:InvokeCommandAction Command="{Binding EditPropertyValueCommand}" CommandParameter="MP_NAME" />
 +
                </core:EventTriggerBehavior>
 +
            </behaviors:BehaviorCollection>
 +
        </Setter.Value>
 +
    </Setter>
 +
</Style>
 +
</source>
 +
</tab>
 +
</tabs>
 +
<br>
 +
 
 +
=== UBIKContentControl ===
 +
In UWP XAML, one often uses a <code><ContentControl  ... ContentTemplateSelector="{StaticResource TaskPropertyTemplateSelector}" /></code> to choose different templates depending on the binding context.
 +
However, it seems to have its limit, namely the template selection happens only once at the beginning. In other words, the template will not change even when the binding context later changes and another template would be the choice.
 +
For such scenarios, we have created a UBIKContentControl. See the example below.
 +
<tabs>
 +
<tab name="UWP">
 +
When the IsLocked status changes on the ContentViewModel, the task direct edit template will be reselected.
 +
<source lang = "xml">
 +
xmlns:controls="using:UBIK.WinX.Controls"
 +
<controls:UBIKContentControl
 +
    Content="{Binding MROViewModel}"
 +
    ContentTemplateSelector="{StaticResource TaskPropertyTemplateSelector}"
 +
    TemplateReselectTrigger="{Binding IsLocked}" />
 +
</source>
 +
</tab>
 +
</tabs>
 +
<br>
 +
 
 +
== Custom Icons ==
 +
Moved to article [[XAML_Tips#Custom_Icons]].
 +
<br>
 +
<br>
 +
 
 +
 
 +
 
 +
 
 +
== Differences between Mobile and UWP ==
 +
As you maybe already noticed we have two different clients, one is WinX UWP and the other one Mobile, which is used to develop clients for three different platforms namely iOS, Android and Windows (-> it doesn’t really differentiate from the previously mentioned UWP except it’s developed in a different framework which is Maui in this case). The customizing stays the same in case of the syntax, but there are some differences in the naming of controls and attributes. Unfortunately, there is no decent documentation of these differences, but the Microsoft documentation and, in general, the internet can support you when searching e.g. for a control in Mobile that you used in UWP.
 +
More specific documentations about Mobile Customizing can be found under [[Mobile XAML]].
 +
 
 +
{{Attention|Please consider that Mobile Windows is not an official product and therefore it can't be guaranteed that all our features work without issues.}}
 +
 
 +
[[Category:Mobile|XAML]]
 +
[[Category:WinX|XAML]]
 +
[[Category:XAML|XAML]]
 +
 
 +
== Namespace changes ==
 +
 +
Starting from the UBIK UWP client{{Version/WinXSince|3.0.0}}, we have restructured & renamed some of our outdated or inaccurate namespaces. This means modifications are necessary for any previous XAML customizing code that refers to these changed namespaces. The complete list of such changes is documented below.
 +
 
 +
{| class="wikitable" | width = "75%"
 +
|-
 +
! !!style="text-align:left;"|V.2.6!!style="text-align:left;"|V.3.0
 +
|-
 +
|rowspan="13" style="text-align:center;"|Name-<br/>space<br/>prefix
 +
|''UBIK.Win8''||''UBIK.WinX''
 +
|-
 +
|''UBIK.WinX.UI''||''UBIK.UI''
 +
|-
 +
|''UBIK.WinX.Utility''||''UBIK.Utility''
 +
|-
 +
|''UBIK.WinX.Library''||''UBIK.Library''
 +
|-
 +
|''UBIK.WinX.DataProvider''||''UBIK.DataProvider''
 +
|-
 +
|''UBIK.WinX.SyncHandler''||''UBIK.SyncHandler''
 +
|-
 +
|''UBIK.WinX.DatabaseConnector''||''UBIK.DatabaseConnector''
 +
|-
 +
|''UBIK.WinX.ContentDatabase''||''UBIK.ContentDatabase''
 +
|-
 +
| ''UBIK.WinX.MRO''||''UBIK.MRO''
 +
|-
 +
| ''UBIK.WinX.Coding''||''UBIK.Coding''
 +
|-
 +
| ''UBIK.WinX.DataService''||''UBIK.DataService''
 +
|-
 +
| ''UBIK.WinX.Redlining''||''UBIK.Redlining''
 +
|-
 +
| ''UBIK.WinX.Positioning''||''UBIK.Positioning''
 +
|-
 +
|}
 +
 
 +
Take the namespace ''UBIK.Win8'' for example, it is now changed to ''UBIK.WinX''. A few affected XAML namespace references are e.g.
 +
* ''using:UBIK.Win8.Views'' -> ''using:UBIK.WinX.Views''
 +
* ''using:UBIK.Win8.GART.Controls'' -> ''using:UBIK.WinX.GART.Controls''
 +
 
 +
'''Important notes''' on the namespace ''UBIK.WinX.UI'':
 +
* One exception is the namespace '''''UBIK.WinX.UI.CollectionView'''''. It is '''not''' changed since the content is indeed WinX specific.
 +
* For namespaces that are changed from ''UBIK.Win8.UI'' such as '''''UBIK.Win8.UI.Controls''''', '''do not''' further '''remove the ''WinX''''' segment even though the results are something like '''''UBIK.WinX.UI.Controls'''''.
 +
 
 +
== Further information regarding XAML ==
 +
* [[Developer Mode]] <br>
 +
* [[Xamarin XAML]] <br>
 +
* [[XAML Basics]] <br>
 +
* [[XAML Best practices]]
 +
 
 +
[[Category:Mobile|XAML]]
 +
[[Category:WinX|XAML]]
 +
[[Category:XAML|XAML]]

Latest revision as of 07:41, 23 September 2025

The WinX User Interface can be vastly customized using XAML. Starting with Version 3.2, this customizing experience can be largely controlled with the new Developer Mode.

Templates

The UI is controlled by several predefined XAML templates which are loaded into the App at startup. There is a set of default template deployed with the App at installation, however, each of them can be overridden by placing the respective file in the folder [AppInstallPath]\LocalState\XAML For further information see UBIK Templates.

General

Controls the overall styling and behavior of the App, like standard Brushes (Colors) and Fonts.

AuthenticationPage

AuthenticationPage
  • UBIKSplashArea.xaml
  • UBIKPageNavigation.xaml -> Deprecated and changed to UBIKHomePageButtons.xaml
  • UBIKProfileItem.xaml


Content Pages

  • UBIKObjectIcon.xaml
  • UBIKObjectIconSmall.xaml


RootPage

RootPage
  • UBIKMainLeftArea.xaml
  • UBIKMainItem.xaml
  • UBIKMainItemSmall.xaml


ChildPage

ChildPage
  • UBIKChildItem.xaml
  • UBIKChildItemSmall.xaml
  • UBIKChildArea.xaml
  • UBIKChildAreaSmall.xaml
  • UBIKChildAction.xaml
  • UBIKPriorityPropertyItem.xaml


DetailsPage

  • UBIKDocumentItem.xaml
  • UBIKDocumentItemSmall.xaml


Specific UBIK® Controls

Basic

CoolGridSplitter (UBIK.WinX.Controls)

Allows to make rows or columns of a grid user-resizable

Example:

<uc:CoolGridSplitter
   x:Name="ChildAreaGridSplitter"
   Height="10"
   HorizontalAlignment="Center" VerticalAlignment="Bottom"
   Background="Transparent"
   Foreground="White"
   ResizeBehavior="CurrentAndNext" ResizeDirection2="Rows"/>

UBIKImageEditor

UWP

It's essentially the SfImageEditor from Syncfusion. Theoretically, customizability mentioned in their official documentations should be supported in UBIK® out of the box. One example is to customize the visibility of the toolbar of such an image editor. The following example hides the toolbar.

xmlns:ctrls="using:UBIK.WinX.UI.Controls"
<ctrls:UBIKImageEditor ...
   xmlns:sfImageEditor="using:Syncfusion.UI.Xaml.ImageEditor">
    <sfImageEditor:SfImageEditor.ToolbarSettings>
        <sfImageEditor:ToolbarSettings IsToolbarVisiblity="False"/>
    </sfImageEditor:SfImageEditor.ToolbarSettings>
</ctrls:UBIKImageEditor>

Mobile(Xamarin)

It's essentially the SfImageEditor from Syncfusion. Theoretically, customizability mentioned in their official documentations should be supported in UBIK® out of the box. One example is to customize the visibility of the toolbar of such an image editor. The following example hides the toolbar.

xmlns:ctrls="clr-namespace:UBIK.CPL.Controls;assembly=UBIK.CPL"
<ctrls:UBIKImageEditor ...
   xmlns:sfImageEditor="clr-namespace:Syncfusion.SfImageEditor.XForms;assembly=Syncfusion.SfImageEditor.XForms">
    <sfImageEditor:SfImageEditor.ToolbarSettings>
        <sfImageEditor:ToolbarSettings IsVisible="false" />
    </sfImageEditor:SfImageEditor.ToolbarSettings>
</ctrls:UBIKImageEditor>

The MergeAnnotationsOnSave property allows to configure whether annotations should be shared through the UBIK® property from the respective Annotation classification (false), or if they should be merged directly into the original file (true, this is the default option):

<ctrls:UBIKImageEditor MergeAnnotationsOnSave="true" <!--true to merge automatically, false to use the classification-->
   ...
</ctrls:UBIKImageEditor>



UBIKPdfViewer

UWP

  • The Top-Toolbar can be customized by setting: UBIKAppBarBackgroundThemeBrush
  • The Annotation-Toolbar can be customized by setting: UBIKPdfAnnotationToolbarBackgroundThemeBrush
  • The color of the buttons in the toolbar is defined by: UBIKAppBarButtonForegroundThemeBrush
  • The Save button can be hidden with SaveButtonVisibility="Collapsed"
  • The Annotation button can be hidden with AnnotationButtonVisibility="Collapsed"
  • The HS button can be hidden with HotspotButtonVisibility="Collapsed"
  • The undo and redo operations can be turned on/off with IsUndoEnabled="true/false". The default value is false. When turned off, the two relevant buttons will be hidden in the toolbar.
IC Attention.pngPlease be careful when you enable undo and redo. Because Ctrl + Z (or whichever other combination in your keyboard layout) is the shortcut to trigger an undo. Therefore, it's possible that you accidentally undo/revert your changes in the PDF viewer when you are typing.
  • The default stroke width for Annotations can be defined with the AnnotationDefaultStrokeWidth property in the UBIKThemes.xaml:
<x:Double x:Key="AnnotationDefaultStrokeWidth">1</x:Double>

Mobile(Xamarin)

On a Xamarin UBIKPdfViewer instance (e.g. in the UBIKDocumentContentArea template), you can configure its EnableSeparateInkStrokes value.

  • True (default): Every ink stroke has its own session. You can select it and change its color/thickness/transparency/etc. separately from others.
  • False: If you do not end the session explicitly by exiting the ink mode, all strokes belong in the same session. And they can only be interacted with as a whole.
xmlns:ctrls="clr-namespace:UBIK.CPL.Controls;assembly=UBIK.CPL"
<ctrls:UBIKPdfViewer
   ...
   EnableSeparateInkStrokes="True" />



Advanced

EvalExpression

Allows to evaluate a C# expression in XAML, using any amount of EvalExpressionParameters



Converters

These are classes in our code used to convert one form of data into another (For example: string to color, bool to string, color to string…). We are using it often on Data Bindings, so we can simply ‘change’ the data that got provided by the model. Mostly, in our environment, we use the Converters for the Visibility Property, Background Property or the Source Property (converting Byte to an Image).

Initialization of a converter in a XAML file:

 <converters:ItemCountLesserThanToVisibilityConverter
x:Key="ItemCountLesserThanToColConverter"
EqualOrBiggerThan="Visible"
LesserThan="Collapsed" />
<!-- This Converter example specifically counts the items that will go into a container (ListView etc..) and gets a parameter passed when it should be a certain visibility. Next example shows you how to configure your converter.-->


Using the ItemCountLesserThanToVisiblity in a visibility attribute:

 <Visibility="{Binding Source={StaticResource RootListFilter}, Path=Count, Converter={StaticResource ItemCountLesserThanToColConverter }, ConverterParameter=13, FallbackValue=Collapsed}"/>
<!--In this case is the parameter 13, so when it gets passed the Count gets checked e.g. how many items there are and when it’s under 13 it will collapse. -->


Example of an EqualToVisConverter being used in order to set the visibility of a grid:

 <Grid Visibility="{Binding Values [MP_SCOPECHANGE], Converter={StaticResource EqualToVisConverter}, ConverterParameter=30}">
</Grid>
<!--The grid will be ONLY visible if the value of this MetaProperty equals the value of the converter parameter. -->


Example of a StringFormatConverter, which converts a value into a string and also accepts a parameter, in this case the GlobalDateTimeFormat, which ‘tells’ the converter how to format the string:

 <TextBlock Grid.Row="1" Text="{Binding Values [MP_LATE_START_MATAP], Converter={StaticResource StringFormatConverter}, ConverterParameter={StaticResource GlobalDateTimeFormat} }"/>

List of all converters

For a complete and up-to-date list of all converters, please refer to the developer mode.


Advanced

Returns a formatted string where placeholders will be filled with values supplied to its parameter properties (Param0, Param1, Param2).

Example:

    <StackPanel Orientation="Horizontal">
        <StackPanel.Resources>
            <!--  Instantiate the converter and bind the the Param0 to a SearchBox on this page  -->
            <converters:StringFormatConverter x:Key="URIConverter" Param0="{Binding ElementName=SkypeQuery, Path=QueryText}" />
        </StackPanel.Resources>
        <!--  Create a SearchBox that calls the typed Name via Skype on enter  -->
        <SearchBox
           x:Name="SkypeQuery"
           Width="240" Height="40"
           FontSize="18"
           PlaceholderText="Call Skype">
            <Interactivity:Interaction.Behaviors>
                <Core:EventTriggerBehavior EventName="QuerySubmitted">
                    <Core:InvokeCommandAction
                         Command="{Binding NavigateToURICommand}"
                         CommandParameter="{Binding ElementName=SkypeQuery, Path=QueryText, Converter={StaticResource URIConverter},
                         ConverterParameter=skype\:\{0\}\?call }" />

                </Core:EventTriggerBehavior>
            </Interactivity:Interaction.Behaviors>
        </SearchBox>
    </StackPanel>


Evaluates a C# expression with 3 optional variables (Param0, Param1, Param2) and returns the result. The object fed into the converter can be referenced in the expression as Context.

Example:

    <Grid>
        <Grid.Resources>
            <!--  Instantiate the converter and bind the Context to the current DataContext, the Param0 to a UI element of this page  -->
            <converters:EvalExpressionConverter x:Key="CodeConverter" Context="{Binding}" Param0="{Binding ElementName=ChildListView, Path=Name}" />
        </Grid.Resources>
        <StackPanel Orientation="Horizontal">
            <!--  Create a TextBox where we can enter a C# expression  -->
            <TextBox
               x:Name="CodeQuery"
               MinWidth="240" Height="40"
               FontSize="18"
               PlaceholderText="Expression">
            </TextBox>
            <!--  Create a TextBlock where we display the result of the compiled expression -->
            <TextBlock Text="{Binding ElementName=CodeQuery, Path=Text, Converter={StaticResource CodeConverter}}" />
        </StackPanel>
    </Grid>


Outdated and replaced by the ListCollectionView.


Converts a template selector to use templates with a certain suffix (e.g. "_Grid" to use "UBIKChildItem_Grid.xaml" instead of "UBIKChildItem.xaml"). The small template file name will be combined as <TemplateName><Suffix>Small.xaml (e.g. "UBIKChildItem_GridSmall.xaml").

Example:

    <Grid>
        <Grid.Resources>
            <!--  Instantiate the template selectors and bind them to the instance of the coverter  -->
            <tpl:ChildItemTemplateSelector x:Key="ChildItemTemplateSelector" />
            <tpl:ChildItemTemplateSmallSelector x:Key="ChildItemTemplateSmallSelector" />
            <converters:ChildItemTemplateSelectorSuffixConverter x:Key="ChildItemTemplateSelectorSuffixConv" TemplateSelector="{Binding Source={StaticResource ChildItemTemplateSelector}}" TemplateSmallSelector="{Binding Source={StaticResource ChildItemTemplateSmallSelector}}"/>
        </Grid.Resources>
        <!-- The itemselector template binds to the suffix that should be used (in this case a binding to a stored profile parameter is used to switch the item template suffix between "_Grid" and "_List" -->

        <StackPanel>
            <CheckBox Grid.Column="0">
                <Interactivity:Interaction.Behaviors>
                    <Core:EventTriggerBehavior EventName="Checked">
                        <!-- Store the Profile Variable "ChildItemsViewMode" to Grid or List - depending on the check state of the check box -->
                        <Core:InvokeCommandAction Command="{Binding StoreProfileParameterCommand}" CommandParameter="ChildItemsViewMode=_Grid"/>
                    </Core:EventTriggerBehavior>
                    <Core:EventTriggerBehavior EventName="Unchecked">
                        <Core:InvokeCommandAction Command="{Binding StoreProfileParameterCommand}" CommandParameter="ChildItemsViewMode=_List"/>
                    </Core:EventTriggerBehavior>
                </Interactivity:Interaction.Behaviors>
            </CheckBox>
            <ListView
                   x:Name="ChildListView"
                   HorizontalContentAlignment="Stretch"
                   ItemTemplateSelector="{Binding Path=StoredProfileParameters[ChildItemsViewMode], Converter={StaticResource ChildItemTemplateSelectorSuffixConv}, ConverterParameter=Normal, FallbackValue=List}"
                   ItemsPanel="{StaticResource ChildPageItemsPanelTemplate}"
                   ItemsSource="{Binding Children.Items}"
                   ScrollViewer.VerticalScrollBarVisibility="Auto" SelectionMode="None">
                <ListView.ItemContainerStyle>
                    <Style TargetType="ListViewItem">
                        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                        <Setter Property="Padding" Value="0" />
                        <Setter Property="Margin" Value="0,0,16,0" />
                    </Style>
                </ListView.ItemContainerStyle>
                <ListView.ItemContainerTransitions>
                    <TransitionCollection>
                        <EntranceThemeTransition FromHorizontalOffset="400" />
                    </TransitionCollection>
                </ListView.ItemContainerTransitions>
            </ListView>
        </StackPanel>
    </Grid>



Properties

Working with Properties is a foundational role of the UI customizer. Be aware that the term can refer to various elements of a content object's datamodel, including details like its Title, SubTitle, UID, classification info, etc. However, this article deals specifically with content properties; those which are displayed under the Property tab in the UBIK client.

Displaying Properties

Displaying with properties is an extremely common requirement in custom UIs. UBIK offers several different bindings, each with specific benefits. It may be enough to simply display the value of a simple string or numeric property somewhere in your UI, or else you might need to display complex properties or execute a certain property-based command.

The table below clarifies the various functionalities and how they can best be used in different scenarios.

It is important to note that for these bindings we are assuming a content viewmodel (ie. an object observed in the client, either after navigating to it, or else when viewing it as an item in the child list of another content object).

Collection Performance Capability Lazy-Loaded
Values Great Very limited - Read only, Property value only No
PropertyItems Good Limited - Read only No
PropertyByName Ok up to 5 uses Unlimited - Full PropertyViewModel Yes
Properties.XItems Impacted Unlimited - Full PropertyViewModel Yes

Values[MP_PROPERTY]

  • This is the most basic and performant way to bind to a property value.
  • This collection simply displays the 'true' value of a property, meaning that it is only useful displaying for simple properties, such as String, Int, Dbl, unformatted DateTime, etc. Properties that have a DisplayValue that is different from their true value, such as GUIDs or selective list items with labels, are not best displayed using this binding.
  • For complex iproperties, it can be still be used in the xaml for non-display purposes, such as in combination with converters or commands. It is immediately present on the most basic content viewmodel (the ContentListItemViewModels used by child lists) without having to be loaded, and remains the best choice in most cases.

Don't Do

Command="{Binding NavigateToGuidCommand}" Command Parameter="{Binding Properties.AllItems[MP_GUID].Value}"

Instead do

Command="{Binding NavigateToGuidCommand}" Command Parameter="{Binding Values[MP_GUID]}"

PropertyItems[MP_PROPERTY]...

This collection can be used when the Value collection does not suffice for displaying appropriate values. This PropertyViewModel presents more options than the simple Values collection, however, it should still only be used for displaying text in the UI as it bypasses the modern functionality offered by UBIK, such as user rights, locked states, etc.

Properties.XItems[MP_PROPERTY]...

These collections were created as a response to the criticism that earlier collections like Values and PropertyItems did not expose enough of a content object's viewmodel to be useful to our ever more sophisticated custom UIs. These collections now provide the full PropertyViewModel, where all aspects of a property (including it's properties, such as Unit attached to Double, the seperate Min/Value/Max valueitems, Date and Time extracted from the DateTime property, Lon/Lat or Alt extracted from the Geo property, and many more) can be accessed in Bindings.

  • However, the downside of accessing this huge viewmodel is the noticeable performance impact, as it loads all instances of properties for the context object, even though only one (MP_PROPERTY) is requested. This impact is felt especially when such as binding is used on an item template in a list with many content objects, of which each has many properties.
  • These collections are Lazy Loaded*, which means that they are not loaded by default, however, a single binding to that collection will load it. When used on an item template in a list, all viewmodels for all properties for all child items will simultaneously be loaded, leading to the performance impact described in this article.
  • "Properties.XItems" is not a real collection. The most frequently used collections are Properties.AllItems, Properties.VisibleItems, Properties.EditableItems, and Properties.ImportantItems (properties which fall into the Priority threshold). The number of properties delivered to a content object in each collection (for example; all, 80%, 40% and 10%, respectively) is also a consideration when estimating the performance impact of binding to these collections; simply put, use the smallest collection possible where the desired property is consistently located.

PropertyByName[MP_PROPERTY]...

This collection was created to overcome the performance impact arising from using Properties.XItems, by individually loading the PropertyViewModel for the named property. However, note that the benefit only lasts while the binding is used sparingly; rendering performance will be roughly the same as loading the Properties collection after 3-5 uses on a single item template.

IC Hint square.pngThe Values[ ] collection delivers the property's value as a string. The equivalent for the other bindings (above shown as '...') is {Binding Collection[PROPERTY_NAME].DisplayValue}, however, the capability of these viewmodels goes far beyond the DisplayValue. Use Developer Mode to learn more.


* Troubleshooting null property values

Because certain property collections are Lazy-loaded as described above, it may be the case that bindings to these properties appear null in certain circumstances, especially if the collection is loaded after the page is rendered, such as through a command or behavior. To troubleshoot this issue, you can ensure that the property collection is accessed during rendertime rather than runtime (simply put, while the page is being constructed rather than during normal use) by applying the same binding to, for example, a Label. This measure should still work if the Label is hidden from view using a visibility binding.



Editing Properties

There are currently 3 main ways to trigger property editing (aside from direct editing) in XAML:

  • EditPropertyValueCommand uses a MetaProperty name as a parameter, to trigger the editing dialogue for that metaproperty.
    • It is located on the ContentViewModel, and automatically triggers a Save and Commit once the edit is confirmed.
  • Similarly, the (PropertyViewModel).ShowEditorCommand/.PropertyClickedCommand triggers the editing dialogue, however, being located on the PropertyViewModel, it is necessary to first access a single property, such as by triggering the command on a list item template, or by directly binding to a specific one using a metaproperty indexer.
    • These two commands are equivalent, the ShowEditorCommand being more general and redirecting for Live Values or properties with Value Records, or else triggering the PropertyClickedCommand.
    • These commands can be seen in action as the standard UI for properties when clicking on the icon to trigger "indirect" editing for any individual metaproperty.
    • Property changes are not saved automatically, but set the ToSave flag on the ContentViewModel, meaning that a SaveAndCommit command is required to commit the changes.
  • The Set Property Value Command sets a named property to a specific or calculated (such as through an EvalExpression) value.



Commands

IC Hint square.pngThe previously listed available commands for binding is removed from here. Since it's more accurate and up-to-date to use the Developer Mode to inspect them in your version of the clients.

Examples for commands with complex parameters

CaptureMediaCommand

UWP

<Button
   ...
   xmlns:controls="using:UBIK.WinX.Controls"
   Command="{Binding CaptureMediaCommand}">
    <Button.CommandParameter>
        <controls:KeyValueList>
            <controls:KeyValueParameter Key="MediaCaptureMode" Value="Video" />
            <controls:KeyValueParameter Key="ChildMetaDefUid" Value="6170a068-2314-4444-ad62-0da99769a048" />
        </controls:KeyValueList>
    </Button.CommandParameter>
</Button>

Mobile(Xamarin)

<Button
   ...
   xmlns:classes="clr-namespace:UBIK.CPL.Classes;assembly=UBIK.CPL"
   Command="{Binding CaptureMediaCommand}">
    <Button.CommandParameter>
        <classes:KeyValueList>
            <classes:KeyValueParameter Key="MediaCaptureMode" Value="Video" />
            <classes:KeyValueParameter Key="ChildMetaDefUid" Value="6170a068-2314-4444-ad62-0da99769a048" />
        </classes:KeyValueList>
    </Button.CommandParameter>
</Button>
IC Hint square.pngThe KeyValueList parameter is supported only . In previous versions, simple string parameters were supported.
IC Attention.pngWhether the creation succeeds also depends on the server configuration. For example, if "*.mp4" is not included as a selective list item in the file type meta property, video document creation will not be possible. Similarly, audio document creation requires a file type "*.wav" to be included in the selective list.
  • MediaCaptureMode: Photo, Video, Audio. Defaults to Photo if unspecified;
  • ChildMetaDefUid: The Guid of the child meta definition to be used for creating the captured media document. If unspecified, the client will simply pick the first child meta definition that is of media type and is allowed under the current context/parent object.



Object Filtering

Filtering of objects is a common requirement in UBIK projects. The table below shows the three main approaches, with the functionality each offers.

Type Configuration/Requirements Persisted Multiple/Complex Values Property type Possible Item Source
Query Fully defined on the server Yes Limited (DateTime, Dbl, Int) where a range is possible. Content properties only Content objects, Documents
Property-Based Content Filters Defined in XAML, requires custom Child Area template name Yes No Content properties only Content objects only
Dynamic Filters Fully defined in XAML No Yes Any bindable data (eg. Content properties, metadefinitions, etc). Content objects, Properties, Documents, etc

A Query is a container that delivers a defined collection of content objects. Properties can be added to the query to serve as filter criteria, where a user can perform their search by editing these properties.

Property Based Content Filters are a xaml-based customization that connects a user input control (usually a textbox) with a specific content property on the content object. This user input is converted into filter criteria and applied directly to the child list, where only matched objects are retained.

Dynamic Filtering is the most flexible, but also the most complex, method of XAML-based filtering. A set of EvalExpressions converts user inputs into a complex filter string, which is then applied immediately to whichever ItemsSource is defined in the ListCollectionView/SfDataSourceExt. Note that in this approach, user inputs are not directly connected to any data, which means that reloading the page in any way (eg. by navigation) causes the input controls to return to their xaml-defined state.

IC Attention.pngWhile any of the above approaches can be used, it is never recommended to mix approaches, as this causes multiple rounds of filtering per keystroke that will noticeably impact performance, especially when many objects and filters are involved!



Miscellaneous


Behaviors in style definitions

It's very common and easy to attach behaviors to different UI controls to extend their functionalities. For example, see StringFormatConverter.

For better code reusability, it's sometimes necessary to implement the functionality of a control in a style so that it can be applied to the same control used in various occasions. In this case, the regular behaviors won't work and you have to use a special type AttachBehavior with some limitations. Below is such an example.

UWP

In this example, a style for the Grid control is defined with a behavior which executes the EditPropertyValueCommand upon tapped. There are two things to note here:

  • When attaching multiple behaviors to controls, you have to explicitly declare a BehaviorCollection and place all behaviors underneath. Unlike outside of style definitions, this is mandatory. Without it, only the last behavior will be effective.
  • Bindings work the same way in general. However, it's not possible to bind to named elements through the "{Binding ElementName=someName, Path=..." syntax and there doesn't seem to be a way to achieve similar goals.
xmlns:behaviors="using:UBIK.WinX.Behaviors"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
<Style x:Key="UBIKNamePropertyGrid" TargetType="Grid">
    <Setter Property="behaviors:AttachBehavior.Behaviors">
        <Setter.Value>
            <behaviors:BehaviorCollection>
                <core:EventTriggerBehavior EventName="Tapped">
                    <core:InvokeCommandAction Command="{Binding EditPropertyValueCommand}" CommandParameter="MP_NAME" />
                </core:EventTriggerBehavior>
            </behaviors:BehaviorCollection>
        </Setter.Value>
    </Setter>
</Style>


UBIKContentControl

In UWP XAML, one often uses a <ContentControl ... ContentTemplateSelector="{StaticResource TaskPropertyTemplateSelector}" /> to choose different templates depending on the binding context. However, it seems to have its limit, namely the template selection happens only once at the beginning. In other words, the template will not change even when the binding context later changes and another template would be the choice. For such scenarios, we have created a UBIKContentControl. See the example below.

UWP

When the IsLocked status changes on the ContentViewModel, the task direct edit template will be reselected.

xmlns:controls="using:UBIK.WinX.Controls"
<controls:UBIKContentControl
   Content="{Binding MROViewModel}"
   ContentTemplateSelector="{StaticResource TaskPropertyTemplateSelector}"
   TemplateReselectTrigger="{Binding IsLocked}" />


Custom Icons

Moved to article XAML Tips.



Differences between Mobile and UWP

As you maybe already noticed we have two different clients, one is WinX UWP and the other one Mobile, which is used to develop clients for three different platforms namely iOS, Android and Windows (-> it doesn’t really differentiate from the previously mentioned UWP except it’s developed in a different framework which is Maui in this case). The customizing stays the same in case of the syntax, but there are some differences in the naming of controls and attributes. Unfortunately, there is no decent documentation of these differences, but the Microsoft documentation and, in general, the internet can support you when searching e.g. for a control in Mobile that you used in UWP. More specific documentations about Mobile Customizing can be found under Mobile XAML.

IC Attention.pngPlease consider that Mobile Windows is not an official product and therefore it can't be guaranteed that all our features work without issues.

Namespace changes

Starting from the UBIK UWP client, we have restructured & renamed some of our outdated or inaccurate namespaces. This means modifications are necessary for any previous XAML customizing code that refers to these changed namespaces. The complete list of such changes is documented below.

V.2.6 V.3.0
Name-
space
prefix
UBIK.Win8 UBIK.WinX
UBIK.WinX.UI UBIK.UI
UBIK.WinX.Utility UBIK.Utility
UBIK.WinX.Library UBIK.Library
UBIK.WinX.DataProvider UBIK.DataProvider
UBIK.WinX.SyncHandler UBIK.SyncHandler
UBIK.WinX.DatabaseConnector UBIK.DatabaseConnector
UBIK.WinX.ContentDatabase UBIK.ContentDatabase
UBIK.WinX.MRO UBIK.MRO
UBIK.WinX.Coding UBIK.Coding
UBIK.WinX.DataService UBIK.DataService
UBIK.WinX.Redlining UBIK.Redlining
UBIK.WinX.Positioning UBIK.Positioning

Take the namespace UBIK.Win8 for example, it is now changed to UBIK.WinX. A few affected XAML namespace references are e.g.

  • using:UBIK.Win8.Views -> using:UBIK.WinX.Views
  • using:UBIK.Win8.GART.Controls -> using:UBIK.WinX.GART.Controls

Important notes on the namespace UBIK.WinX.UI:

  • One exception is the namespace UBIK.WinX.UI.CollectionView. It is not changed since the content is indeed WinX specific.
  • For namespaces that are changed from UBIK.Win8.UI such as UBIK.Win8.UI.Controls, do not further remove the WinX segment even though the results are something like UBIK.WinX.UI.Controls.

Further information regarding XAML