Difference between revisions of "XAML Tips"
m (→Custom Icons) |
|||
(65 intermediate revisions by 10 users not shown) | |||
Line 1: | Line 1: | ||
− | + | == Attachable behaviors == | |
− | + | ||
− | + | ||
It's quite often that you need to attach behaviors to certain XAML elements. For example, on a Grid, you want to attach a behavior which executes a command upon a Tapped event, or you want to execute a command when a certain property on a UBIK object changes. | It's quite often that you need to attach behaviors to certain XAML elements. For example, on a Grid, you want to attach a behavior which executes a command upon a Tapped event, or you want to execute a command when a certain property on a UBIK object changes. | ||
Line 14: | Line 12: | ||
</DataTemplate> | </DataTemplate> | ||
</source> | </source> | ||
+ | <br> | ||
− | + | === Event Triggered === | |
With an EventTriggerBehavior, you can react on changes/events of UI Elements: | With an EventTriggerBehavior, you can react on changes/events of UI Elements: | ||
Line 27: | Line 26: | ||
</Grid> | </Grid> | ||
</source> | </source> | ||
+ | <br> | ||
− | + | === Data Triggered === | |
If you want to react on changes of the underlying data (ViewModel), you can use DataTriggerBehavior instead. The following example, when used in the ''UBIKSplashArea'' template, automatically navigates to the root objects once the login process is finished and the user was successfully authenticated: | If you want to react on changes of the underlying data (ViewModel), you can use DataTriggerBehavior instead. The following example, when used in the ''UBIKSplashArea'' template, automatically navigates to the root objects once the login process is finished and the user was successfully authenticated: | ||
Line 40: | Line 40: | ||
</Grid> | </Grid> | ||
</source> | </source> | ||
+ | <br> | ||
+ | <br> | ||
+ | == Content creation == | ||
+ | === Child item creation === | ||
+ | {{Version/WinXSince|3.5.5}} | ||
+ | To directly create an object on a child of the current object, you can define a Button as follows. The method "Item.IsTypeCreationAllowed" used in the expression gets the uid of the type that should be created below a child, if a child does not allow the creation of that type underneath it, the child will be hidden in the selection dialog. To actually create the object, the "CreateChildItemCommand" needs to be passed a KeyValueList with two parameters: The Parent-key is the UID or the ContentViewModel of the child underneath the object should be created, the Type-key is the type of object which should be created--this should match the uid passed to the "Item.IsTypeCreationAllowed" method. | ||
− | = | + | <source lang = "xml"> |
− | + | xmlns:uc="using:UBIK.WinX.Controls" | |
− | + | xmlns:cv="using:UBIK.WinX.UI.CollectionView" | |
+ | </source> | ||
<source lang = "xml"> | <source lang = "xml"> | ||
− | < | + | <x:String x:Key="PlantMap">Item.IsTypeCreationAllowed("21fc990a-d064-4bee-8d48-3293351f827a")</x:String> |
− | + | <cv:ListCollectionView x:Key="PlantMapView" Expression="{StaticResource PlantMap}" ItemsSource="{Binding Children.Items}" /> | |
− | + | ||
− | + | <AppBarButton> | |
− | + | <AppBarButton.Flyout> | |
− | + | <Flyout Placement="Full"> | |
− | + | <ListView ItemsSource="{Binding Source={StaticResource PlantMapView}}"> | |
− | + | <ListView.ItemTemplate> | |
− | + | <DataTemplate> | |
− | + | <Button Content="{Binding Header}" Command="{Binding CreateChildItemCommand}" x:Name="CreateButton" Tag="{Binding}"> | |
− | + | <Button.CommandParameter> | |
− | + | <uc:KeyValueList> | |
− | + | <uc:KeyValueParameter Key="Parent" Value="6D733909-1742-4110-8619-237849BFE453"/> | |
− | </DataTemplate> | + | <uc:KeyValueParameter Key="Type" Value="21fc990a-d064-4bee-8d48-3293351f827a"/> |
+ | </uc:KeyValueList> | ||
+ | </Button.CommandParameter> | ||
+ | </Button> | ||
+ | </DataTemplate> | ||
+ | </ListView.ItemTemplate> | ||
+ | </ListView> | ||
+ | </Flyout> | ||
+ | </AppBarButton.Flyout> | ||
+ | </AppBarButton> | ||
</source> | </source> | ||
− | |||
− | |||
− | |||
<source lang = "xml"> | <source lang = "xml"> | ||
<x:String x:Key="PlantMap">Item.IsTypeCreationAllowed("21fc990a-d064-4bee-8d48-3293351f827a")</x:String> | <x:String x:Key="PlantMap">Item.IsTypeCreationAllowed("21fc990a-d064-4bee-8d48-3293351f827a")</x:String> | ||
Line 91: | Line 104: | ||
</AppBarButton> | </AppBarButton> | ||
</source> | </source> | ||
+ | |||
+ | <br/> | ||
+ | Additionally, the following optional parameters can be added as well. | ||
+ | * CreateOnly (optional, defaults to false): When set to true, the client will not automatically navigate to the created content, rather automatically save and commit it. If set to true, this overrides the following parameters; | ||
+ | * AutoNavigate (optional, defaults to true): When set to false, the client will not automatically navigate to the created content; | ||
+ | * AutoCommit (optional, defaults to false): When set to true, the change(s) will be saved to the local cache and the database, and then committed to the server. | ||
+ | <br> | ||
+ | |||
+ | === Creating multiple documents === | ||
+ | To upload multiple documents at once, the CreateChildItemsCommand can be used. The list of supported command parameters are similar to those of the CreateChildItemCommand (single item). Except that anything other than AutoNavigate=false and AutoCommit=true do not make sense in multi-creation scenario. Therefore, those parameters are fixed and any received from XAML will be ignored. | ||
+ | |||
+ | <!-- <tabs> | ||
+ | |||
+ | <tab name="UWP">--> | ||
+ | <source lang = "xml"> | ||
+ | <Button ... | ||
+ | xmlns:uc="using:UBIK.WinX.Controls" | ||
+ | Command="{Binding CreateChildItemsCommand}" | ||
+ | Content="Create multiple documents"> | ||
+ | <Button.CommandParameter> | ||
+ | <uc:KeyValueList> | ||
+ | <uc:KeyValueParameter Key="Type" Value="6170a068-2314-4444-ad62-0da99769a048" /> | ||
+ | </uc:KeyValueList> | ||
+ | </Button.CommandParameter> | ||
+ | </Button> | ||
+ | </source> | ||
+ | <!--</tab> | ||
+ | |||
+ | <tab name="Xamarin"> | ||
+ | <source lang = "xml"> | ||
+ | <Button ... | ||
+ | xmlns:classes="clr-namespace:UBIK.CPL.Classes;assembly=UBIK.CPL" | ||
+ | Command="{Binding CreateChildItemsCommand}" | ||
+ | Content="Create multiple documents"> | ||
+ | <Button.CommandParameter> | ||
+ | <classes:KeyValueList> | ||
+ | <classes:KeyValueParameter Key="Type" Value="6170a068-2314-4444-ad62-0da99769a048" /> | ||
+ | </classes:KeyValueList> | ||
+ | </Button.CommandParameter> | ||
+ | </Button> | ||
+ | </source> | ||
+ | </tab> | ||
+ | |||
+ | </tabs>--> | ||
+ | <br> | ||
+ | <br> | ||
=== Disable FilloutCriteria === | === Disable FilloutCriteria === | ||
Line 100: | Line 159: | ||
<Interactivity:Interaction.Behaviors> | <Interactivity:Interaction.Behaviors> | ||
<Core:EventTriggerBehavior EventName="Tapped"> | <Core:EventTriggerBehavior EventName="Tapped"> | ||
− | + | <Core:InvokeCommandAction Command="{Binding ElementName=ChildAreaGrid, Path=DataContext.AddTemplatableDataCommand}" > | |
− | + | <Core:InvokeCommandAction.CommandParameter> | |
− | + | <uc:KeyValueList> | |
− | + | <uc:KeyValueParameter Key="Uid" Value="{Binding Tag,ElementName=selectionGrid}"/> | |
− | + | <uc:KeyValueParameter Key="EnableFillOutCriteria" Value="false"/> | |
− | + | <uc:KeyValueParameter Key="SkipDialog" Value="false"/> | |
− | + | </uc:KeyValueList> | |
− | + | </Core:InvokeCommandAction.CommandParameter> | |
− | + | </Core:InvokeCommandAction> | |
</Core:EventTriggerBehavior> | </Core:EventTriggerBehavior> | ||
</Interactivity:Interaction.Behaviors> | </Interactivity:Interaction.Behaviors> | ||
</Grid> | </Grid> | ||
</source> | </source> | ||
+ | <br> | ||
+ | <br> | ||
− | + | == Hotspotting == | |
− | + | {{Attention|To use a binding in the KeyValueParameter, it has to be applied like in the example provided here: [[KeyValueList]]}} | |
− | + | ||
The hotspotting command is used for hotspotting as well as for annotating, to configure the button for hotspotting, the commandparameter "Mode" should be set to "HotSpotting", for annotating the "Mode" should be "Annotate". The parameter commit is optional, if set to true, the changes get automatically persisted when leaving the editing mode. | The hotspotting command is used for hotspotting as well as for annotating, to configure the button for hotspotting, the commandparameter "Mode" should be set to "HotSpotting", for annotating the "Mode" should be "Annotate". The parameter commit is optional, if set to true, the changes get automatically persisted when leaving the editing mode. | ||
Line 132: | Line 192: | ||
</AppBarToggleButton> | </AppBarToggleButton> | ||
</source> | </source> | ||
+ | <br> | ||
+ | <br> | ||
− | + | == Remember scroll positions of list views == | |
− | The UBIK-Client does include a function to remember the position in a list (ListView) when navigating away from it. This function is only available when the list (ListView) has a unique name as a property (x: | + | === Version 3.7 & later {{Version/WinXSince|3.7}} === |
+ | Starting from this version, | ||
+ | * The precision of scroll position remembering is improved(by pixel offsets instead of by items); | ||
+ | * It also works for other scrollable lists (instead of just for content object lists). | ||
+ | <br /> | ||
+ | To enable this feature, you should make sure the following. | ||
+ | * The SelectionBoundListView is used instead of the standard ListView. Its {{UBIK}} namespace is <code>UBIK.WinX.Controls</code>; | ||
+ | * The SelectionBoundListView's <code>RememberScrollPosition</code> property is not set to "false"; (It's "true" by default.) | ||
+ | * The SelectionBoundListView's <code>x:Name</code> property value is unique. | ||
+ | <br> | ||
+ | |||
+ | === Version 3.6 {{Version/WinXSince|3.6}} === | ||
+ | The UBIK-Client does include a function to remember the position in a list (ListView) when navigating away from it. This function is only available when the list (ListView) has a unique name as a property (x:Name). When browsing back to the previously visited list UBIK scrolls back to the last position. The function does not save scroll positions over different sessions. | ||
Implementing the function to remember the scroll position in a ListView one has to consider that the list elements (Children) could depend on a other UI-element. If the list elements do depend on a other UI-elemente, this element has to be created above the ListView in the XAML. | Implementing the function to remember the scroll position in a ListView one has to consider that the list elements (Children) could depend on a other UI-element. If the list elements do depend on a other UI-elemente, this element has to be created above the ListView in the XAML. | ||
<source lang = "xml"> | <source lang = "xml"> | ||
− | <DataTemplate xmlns:behaviors="using:UBIK.WinX.Behaviors"> | + | <DataTemplate xmlns:behaviors="using:UBIK.WinX.Behaviors" xmlns:uc="using:UBIK.WinX.Controls"> |
... | ... | ||
− | < | + | <uc:SelectionBoundListView x:Name="ChildListView"> |
<Interactivity:Interaction.Behaviors> | <Interactivity:Interaction.Behaviors> | ||
<behaviors:FirstVisibleItemPersistenceBehavior FirstVisibleItems="{Binding ScrollItems}" /> | <behaviors:FirstVisibleItemPersistenceBehavior FirstVisibleItems="{Binding ScrollItems}" /> | ||
</Interactivity:Interaction.Behaviors> | </Interactivity:Interaction.Behaviors> | ||
− | </ | + | </uc:SelectionBoundListView> |
</DataTemplate> | </DataTemplate> | ||
</source> | </source> | ||
+ | <br> | ||
+ | <br> | ||
− | + | ||
+ | == MultiBinding {{Version/WinXSince|3.6}} == | ||
Very often we want to display some UI elements (e.g. a Grid) depending on whether multiple criteria are met. It's much easier to achieve this by using a MultiBindingBehavior like the following. | Very often we want to display some UI elements (e.g. a Grid) depending on whether multiple criteria are met. It's much easier to achieve this by using a MultiBindingBehavior like the following. | ||
<source lang = "xml"> | <source lang = "xml"> | ||
Line 167: | Line 244: | ||
</source> | </source> | ||
The behavior makes sure the container Grid is set to Visibile only if the mass editing mode is not turned on (MassEditViewModel is null) and the context object has child document(s) (Documents.Items.Count is greater than 0. You can combine any number of binding results (MultiBindingItem) using the VisLogicAndConverter (the name should be self explanatory). | The behavior makes sure the container Grid is set to Visibile only if the mass editing mode is not turned on (MassEditViewModel is null) and the context object has child document(s) (Documents.Items.Count is greater than 0. You can combine any number of binding results (MultiBindingItem) using the VisLogicAndConverter (the name should be self explanatory). | ||
+ | <br> | ||
+ | <br> | ||
+ | == Other Commands == | ||
+ | === InvokeOnItemsCommand {{Version/WinXSince|3.6}} === | ||
+ | Available on all ListViewModels, this command allows executing a specified command on a collection of list items. It can be used in combination with features such as [[Mass_Edit_(UBIK_WinX)|mass editing]] and [[XAML_Changes_in_UBIK_WinX_3.5#After_3.5|expression based collection filtering]]. Examples for both combinations are provided below. | ||
− | + | {{Attention|The command specified through the "Command" parameter is executed on list items and, therefore, must be available in the list item contexts (view models). If in doubt, the [[Developer_Mode|developer mode]] can be used to inspect if a command is available in a certain context.}} | |
− | === FlipView === | + | {{Hint|Parameter "Command" and "SelectedItemsOnly" are specific to the InvokeOnItemsCommand. What other parameters to define or whether to define them at all depends on the type of command to be executed on the items.}} |
+ | <br> | ||
+ | |||
+ | ==== Invoke on selected items ==== | ||
+ | {{Attention|To use a binding in the KeyValueParameter, it has to be applied like in the example provided here: [[KeyValueList]]}} | ||
+ | This example demonstrates how you can use the mass editing feature to select certain objects from the child list and then execute the SetPropertyValueCommand for those selected. | ||
+ | * The example code assumes that the child objects have an editable property called "VALUE" and tries to set 50 as their value; | ||
+ | * You should insert the following code snippet into the default UBIKChildArea template; | ||
+ | * If the parameter "SelectedItemsOnly" is missed or set to "False", the command will be executed on all child items; | ||
+ | * To enable selection, click on the "Mass Edit" button below the property list. | ||
+ | <br /> | ||
+ | |||
+ | <tabs> | ||
+ | <tab name="UWP"> | ||
+ | <source lang = "xml"> | ||
+ | <Button | ||
+ | xmlns:example="using:UBIK.WinX.Controls" | ||
+ | Command="{Binding Children.InvokeOnItemsCommand}" | ||
+ | Content="Set to 50%"> | ||
+ | <Button.CommandParameter> | ||
+ | <example:KeyValueList> | ||
+ | <example:KeyValueParameter Key="Command" Value="SetPropertyValueCommand" /> | ||
+ | <example:KeyValueParameter Key="SelectedItemsOnly" Value="False" /> | ||
+ | <example:KeyValueParameter Key="PropertyName" Value="VALUE" /> | ||
+ | <example:KeyValueParameter Key="PropertyValue"> | ||
+ | <example:KeyValueParameter.Value> | ||
+ | <x:Double>50</x:Double> | ||
+ | </example:KeyValueParameter.Value> | ||
+ | </example:KeyValueParameter> | ||
+ | </example:KeyValueList> | ||
+ | </Button.CommandParameter> | ||
+ | </Button> | ||
+ | </source> | ||
+ | </tab> | ||
+ | |||
+ | <tab name="Xamarin"> | ||
+ | <source lang = "xml"> | ||
+ | <Button | ||
+ | xmlns:example="clr-namespace:UBIK.CPL.Classes;assembly=UBIK.CPL" | ||
+ | Command="{Binding Children.InvokeOnItemsCommand}" | ||
+ | Text="Set to 50%"> | ||
+ | <Button.CommandParameter> | ||
+ | <example:KeyValueList> | ||
+ | <example:KeyValueParameter Key="Command" Value="SetPropertyValueCommand" /> | ||
+ | <example:KeyValueParameter Key="SelectedItemsOnly" Value="False" /> | ||
+ | <example:KeyValueParameter Key="PropertyName" Value="VALUE" /> | ||
+ | <example:KeyValueParameter Key="PropertyValue"> | ||
+ | <example:KeyValueParameter.Value> | ||
+ | <x:Double>50</x:Double> | ||
+ | </example:KeyValueParameter.Value> | ||
+ | </example:KeyValueParameter> | ||
+ | </example:KeyValueList> | ||
+ | </Button.CommandParameter> | ||
+ | </Button> | ||
+ | </source> | ||
+ | </tab> | ||
+ | </tabs> | ||
+ | <br> | ||
+ | <br> | ||
+ | |||
+ | ==== Invoke on filtered results ==== | ||
+ | {{Attention|To use a binding in the KeyValueParameter, it has to be applied like in the example provided here: [[KeyValueList]]}} | ||
+ | |||
+ | * First, you need to setup a filtered list | ||
+ | **UWP: Setup a ListCollectionView in the Resources section of a UI element (e.g. Grid). This list is only available/visible within that UI element (the Grid in this case). | ||
+ | **Xamarin: Setup a String with a filtering expression & a SfDataSourceExt in the ResourceDictionary of the ContentView. For the Expression property of the SfDataSourceExt refer to the created expression String. | ||
+ | |||
+ | * The ItemsSource uses Children.Items. Use the [[Developer_Mode|developer mode]] if necessary to find out if this is available where you intend to define the list; | ||
+ | * The example expression filters for any items that don't contain the text "EXAMPLE" in their Title texts. You can filter differently by altering the expression. | ||
+ | <br /> | ||
+ | |||
+ | <tabs> | ||
+ | <tab name="UWP"> | ||
+ | <source lang = "xml"> | ||
+ | <Grid xmlns:CV="using:UBIK.WinX.UI.CollectionView"> | ||
+ | <Grid.Resources> | ||
+ | <CV:ListCollectionView | ||
+ | x:Key="Filtered" | ||
+ | Expression="!Item.Title.Contains("EXAMPLE")" | ||
+ | ItemsSource="{Binding Children.Items}" /> | ||
+ | </Grid.Resources> | ||
+ | ... | ||
+ | </Grid> | ||
+ | </source> | ||
+ | </tab> | ||
+ | |||
+ | <tab name="Xamarin"> | ||
+ | <source lang = "xml"> | ||
+ | <ContentView | ||
+ | xmlns:controls="clr-namespace:UBIK.CPL.Controls;assembly=UBIK.CPL" | ||
+ | ...> | ||
+ | <ContentView.Resources> | ||
+ | <ResourceDictionary> | ||
+ | <x:String x:Key="Expresssion">!Item.Title.Contains("EXAMLPLE")</x:String> | ||
+ | <controls:SfDataSourceExt x:Key="Filtered" Expression="{StaticResource Expresssion}" ItemsSource="{Binding Children.Items}" /> | ||
+ | </ResourceDictionary> | ||
+ | </ContentView.Resources> | ||
+ | </ContentView> | ||
+ | </source> | ||
+ | </tab> | ||
+ | </tabs> | ||
+ | |||
+ | <br /> | ||
+ | With the filtered list configured, you can then insert the following code snippet to execute the SetPropertyValueCommand for the filtered result items. | ||
+ | * The example code assumes that the child objects have an editable property called "VALUE" and tries to set 50 as their value; | ||
+ | * The "Filtered" refers to the ListCollectionView (UWP) or SfDataSourceExt (Xamarin) configured above. | ||
+ | <br /> | ||
+ | |||
+ | <tabs> | ||
+ | <tab name="UWP"> | ||
+ | <source lang = "xml"> | ||
+ | <AppBarButton | ||
+ | xmlns:example="using:UBIK.WinX.Controls" | ||
+ | Command="{Binding Source={StaticResource Filtered}, Path=ListViewModel.InvokeOnItemsCommand}" | ||
+ | Icon="AllApps" | ||
+ | Label="Set to 50" | ||
+ | Style="{ThemeResource UBIKActionAppBarButton}"> | ||
+ | <AppBarButton.CommandParameter> | ||
+ | <example:KeyValueList> | ||
+ | <example:KeyValueParameter Key="Command" Value="SetPropertyValueCommand" /> | ||
+ | <example:KeyValueParameter Key="PropertyName" Value="VALUE" /> | ||
+ | <example:KeyValueParameter Key="PropertyValue" Value="50" /> | ||
+ | </example:KeyValueList> | ||
+ | </AppBarButton.CommandParameter> | ||
+ | </AppBarButton> | ||
+ | </source> | ||
+ | </tab> | ||
+ | |||
+ | <tab name="Xamarin"> | ||
+ | <source lang = "xml"> | ||
+ | <Button | ||
+ | xmlns:example="clr-namespace:UBIK.CPL.Classes;assembly=UBIK.CPL" | ||
+ | Command="{Binding Source={StaticResource Filtered}, Path=ListViewModel.InvokeOnItemsCommand}" | ||
+ | Text="Set to 50"> | ||
+ | <Button.CommandParameter> | ||
+ | <example:KeyValueList> | ||
+ | <example:KeyValueParameter Key="Command" Value="SetPropertyValueCommand" /> | ||
+ | <example:KeyValueParameter Key="PropertyName" Value="VALUE" /> | ||
+ | <example:KeyValueParameter Key="PropertyValue" Value="50" /> | ||
+ | </example:KeyValueList> | ||
+ | </Button.CommandParameter> | ||
+ | </Button> | ||
+ | </source> | ||
+ | </tab> | ||
+ | </tabs> | ||
+ | |||
+ | {{Attention|The binding <code>ListViewModel.InvokeOnItemsCommand</code> should be updated to <code>BulkOperation.InvokeOnItemsCommand</code> starting from version 4.3.}} | ||
+ | <br> | ||
+ | |||
+ | ==== Support for old styled commands ==== | ||
+ | Some old commands might not support KeyValueLists as parameters. In that case, just define the parameter value under the "CommandParameter" key, e.g. | ||
+ | <br /> | ||
+ | <source lang = "xml"><example:KeyValueParameter Key="CommandParameter" Value="some string value for example" /></source>. | ||
+ | This single value is then passed as the command parameter instead of the entire KeyValueList. | ||
+ | <br> | ||
+ | <br> | ||
+ | |||
+ | === SetPropertyValueCommand {{Version/WinXSince|3.6}} === | ||
+ | {{Attention|To use a binding in the KeyValueParameter, it has to be applied like in the example provided here: [[KeyValueList]]}} | ||
+ | |||
+ | This command existed before but was implemented differently. In the newer version(s), it is improved to provide customizers more control over the things that happen during/after the property value changes. | ||
+ | The available command parameters are: | ||
+ | * PropertyName: the name of the property to set a new value to; | ||
+ | * PropertyValue: the value to be set to the above mentioned property; | ||
+ | * OnlyForUnvalidated (optional, defaults to false): When set to true, the value will only be set if the property is not yet validated; | ||
+ | * AutoSave (optional, defaults to false): When set to true, the change(s) will be saved to the local cache and database; | ||
+ | * AutoCommit (optional, defaults to false): When set to true, the change(s) will be committed to the server. | ||
+ | |||
+ | {{Hint|There's no way to commit changes without saving them locally first. Therefore, the "AutoSave" parameter will be ignored when "AutoCommit" is set to true.}} | ||
+ | |||
+ | Here's an example of the command usage. It tries to set the property called "VALUE" to a double value 50 regardless of its current state and then automatically save and commit the change. | ||
+ | <br /> | ||
+ | <source lang = "xml"> | ||
+ | <AppBarButton | ||
+ | xmlns:example="using:UBIK.WinX.Controls" | ||
+ | Command="{Binding SetPropertyValueCommand}" | ||
+ | Icon="Edit" | ||
+ | Label="Set to 50%"> | ||
+ | <AppBarButton.CommandParameter> | ||
+ | <example:KeyValueList> | ||
+ | <example:KeyValueParameter Key="PropertyName" Value="VALUE" /> | ||
+ | <example:KeyValueParameter Key="PropertyValue"> | ||
+ | <example:KeyValueParameter.Value> | ||
+ | <x:Double>50</x:Double> | ||
+ | </example:KeyValueParameter.Value> | ||
+ | </example:KeyValueParameter> | ||
+ | <example:KeyValueParameter Key="OnlyForUnvalidated" Value="false" /> | ||
+ | <example:KeyValueParameter Key="AutoSave" Value="true" /> | ||
+ | <example:KeyValueParameter Key="AutoCommit" Value="true" /> | ||
+ | </example:KeyValueList> | ||
+ | </AppBarButton.CommandParameter> | ||
+ | </AppBarButton> | ||
+ | </source> | ||
+ | |||
+ | {{Hint|It is advised to provide typed values like <nowiki><x:Double>50</x:Double></nowiki>. But for simple types, you can try writing them in the text format like <nowiki><example:KeyValueParameter Key="PropertyValue" Value="50" /></nowiki> and {{UBIK}} will try to find the right type.}} | ||
+ | <br> | ||
+ | |||
+ | === SaveAndCommitCommand === | ||
+ | With the ''SaveAndCommitCommand'' it is possible to save and commit unsaved changes on a ContentViewModel. | ||
+ | |||
+ | * ForceCommit CommandParameter (optional, defaults to false): Normally when the App is in Online mode, changes are automatically committed when saved. This is not the case when the App is in Manual mode. Setting the ''ForceCommit'' parameter to true makes it possible to commit the changes when saved in Manual mode. | ||
+ | * {{Version/WinXSince|4.7}} {{Version/XamarinSince|4.7}} PropertyNameToSave CommandParameter (optional, defaults to null): Delivers the Property Name as String of a specific Property that should be saved. E.g. when called via PropertyViewModel.ResetCommand or PropertyViewModel.DeleteCommand, the ''PropertyNameToSave'' parameter is used to only apply the SaveAndCommitCommand on the related PropertyViewModel called from, and not on other unsaved changes on this ContentViewModel. | ||
+ | <br/> | ||
+ | <tabs> | ||
+ | <tab name="UWP"> | ||
+ | <source lang = "xml"> | ||
+ | <Button | ||
+ | xmlns:example="using:UBIK.WinX.Controls" | ||
+ | Command="{Binding SaveAndCommitCommand}"> | ||
+ | <Button.CommandParameter> | ||
+ | <example:KeyValueList> | ||
+ | <example:KeyValueParameter Key="ForceCommit" Value="True" /> | ||
+ | </example:KeyValueList> | ||
+ | </Button.CommandParameter> | ||
+ | </Button> | ||
+ | </source> | ||
+ | </tab> | ||
+ | <tab name="Xamarin"> | ||
+ | <source lang = "xml"> | ||
+ | <Button | ||
+ | xmlns:example="using:clr-namespace:UBIK.CPL.Classes;assembly=UBIK.CPL" | ||
+ | Command="{Binding SaveAndCommitCommand}"> | ||
+ | <Button.CommandParameter> | ||
+ | <example:KeyValueList> | ||
+ | <example:KeyValueParameter Key="ForceCommit" Value="True" /> | ||
+ | </example:KeyValueList> | ||
+ | </Button.CommandParameter> | ||
+ | </Button> | ||
+ | </source> | ||
+ | </tab> | ||
+ | </tabs> | ||
+ | <br> | ||
+ | |||
+ | === DisplayViewCommand === | ||
+ | This command can be used to [[Custom_View_(Client)|display cutom views]]. | ||
+ | <br> | ||
+ | |||
+ | === TeachInCommand === | ||
+ | With the '''TeachInCommand''' you're allowed to set your device's current location ("teach-in", "TeachIn") as the value of the context object's [[SYSCLS_GEO|geo property]]. | ||
+ | This command is available in both '''ContentViewModel''' and '''PropertyViewModel'''. | ||
+ | * ContentViewModel.TeachInCommand: If possible, sets the current location of the device as the value of the context object's [[SYSCLS_GEO|geo property]]. Saves and commits the change; | ||
+ | * PropertyViewModel.TeachInCommand: If possible, sets the current location of the device as the value of the current property if it's a geo property (not necessarily the [[SYSCLS_GEO|geo property]]). Addtionally supports a boolean command parameter: | ||
+ | ** False (default): The change is not automatically saved. | ||
+ | ** True: The change is saved. | ||
+ | <br/> {{hint| Make sure you use the correct binding path for your command depending on your current context view model. E.g., if the context view model is already the ContentViewModel then your binding path should simply be TeachInCommand. You can use the [[Developer_Mode|developer mode]] to find out the current view model in a view.}} | ||
+ | <br> | ||
+ | |||
+ | ===UpdateArbitraryObjectCommand {{Version/WinXSince|4.7}}=== | ||
+ | The "UpdateArbitraryObjectCommand" is responsible for updating an arbitrary object based on a set of provided parameters. The command is accessible in the AppStatusViewModel (as '''ViewModel.AppStatus'''). | ||
+ | <br /> | ||
+ | The available command parameters are: | ||
+ | * Uid (Mandatory): UID of the object to be updated; | ||
+ | * UpdateChildDepth (Optional): Child depth/level to update (defaults to 1); | ||
+ | * UpdateParentDepth (Optional): Parent depth/level to update (defaults to 0); | ||
+ | * UpdateIgnoreExpiry (Optional): Ignore update expiry (defaults to false); | ||
+ | |||
+ | {{Hint|Note that if you set the UpdateChildDepth property to "-1" you are also able to update a whole branch with this command.}} | ||
+ | |||
+ | Here is an example of the command usage: | ||
+ | <br /> | ||
+ | <tabs> | ||
+ | <tab name="UWP"> | ||
+ | <source lang = "xml"> | ||
+ | <Button ... | ||
+ | xmlns:uc="using:UBIK.WinX.Controls" | ||
+ | Command="{Binding UpdateArbitraryObjectCommand}" | ||
+ | Content="Update Arbitrary Object"> | ||
+ | <Button.CommandParameter> | ||
+ | <uc:KeyValueList> | ||
+ | <uc:KeyValueParameter Key="Uid" Value="...valid UID..." /> | ||
+ | <uc:KeyValueParameter Key="UpdateChildDepth" Value="2" /> | ||
+ | <uc:KeyValueParameter Key="UpdateParentDepth" Value="0" /> | ||
+ | <uc:KeyValueParameter Key="UpdateIgnoreExpiry" Value="true" /> | ||
+ | </uc:KeyValueList> | ||
+ | </Button.CommandParameter> | ||
+ | </Button> | ||
+ | </source> | ||
+ | </tab> | ||
+ | |||
+ | <tab name="Xamarin"> | ||
+ | <source lang = "xml"> | ||
+ | <Button ... | ||
+ | xmlns:uc="using:clr-namespace:UBIK.CPL.Classes;assembly=UBIK.CPL" | ||
+ | Command="{Binding UpdateArbitraryObjectCommand}" | ||
+ | Content="Update Arbitrary Object"> | ||
+ | <Button.CommandParameter> | ||
+ | <uc:KeyValueList> | ||
+ | <uc:KeyValueParameter Key="Uid" Value="...valid UID..." /> | ||
+ | <uc:KeyValueParameter Key="UpdateChildDepth" Value="2" /> | ||
+ | <uc:KeyValueParameter Key="UpdateParentDepth" Value="0" /> | ||
+ | <uc:KeyValueParameter Key="UpdateIgnoreExpiry" Value="true" /> | ||
+ | </uc:KeyValueList> | ||
+ | </Button.CommandParameter> | ||
+ | </Button> | ||
+ | </source> | ||
+ | </tab> | ||
+ | </tabs> | ||
+ | <br> | ||
+ | |||
+ | === Access to an arbitrary object {{Version/WinXSince|4.6}} {{Version/XamarinSince|4.6}} === | ||
+ | With the ObjectByUID feature it is possible to access any local arbitrary object by its UID and, for example, display a value of it. | ||
+ | It can be accessed from ContentViewModel, AuthenticationViewModel, and RootPageViewModel levels. | ||
+ | |||
+ | To display a string of e.g. a property of an arbitrary object from ContentViewModel, AuthenticationViewModel & RootPageViewModel, the following syntax can be used in related XAMLs: | ||
+ | <tabs> | ||
+ | <tab name="UWP"> | ||
+ | <source lang = "xml"> | ||
+ | <TextBlock Text="{Binding ObjectByUID[paste-your-uid].Properties.VisibleItems[add-your-property-name].DisplayValue}" /> | ||
+ | </source> | ||
+ | </tab> | ||
+ | |||
+ | <tab name="Xamarin"> | ||
+ | <source lang = "xml"> | ||
+ | <Label Text="{Binding ObjectByUID[paste-your-uid].Properties.VisibleItems[add-your-property-name].DisplayValue}" /> | ||
+ | </source> | ||
+ | </tab> | ||
+ | </tabs> | ||
+ | |||
+ | For Property Dialogs the CallingViewModel prefix is needed to access an arbitrary object: | ||
+ | <tabs> | ||
+ | <tab name="UWP"> | ||
+ | <source lang = "xml"> | ||
+ | <TextBlock Text="{Binding CallingViewModel.ObjectByUID[paste-your-uid].Properties.VisibleItems[add-your-property-name].DisplayValue}" /> | ||
+ | </source> | ||
+ | </tab> | ||
+ | |||
+ | <tab name="Xamarin"> | ||
+ | <source lang = "xml"> | ||
+ | <Label Text="{Binding CallingViewModel.ObjectByUID[paste-your-uid].Properties.VisibleItems[add-your-property-name].DisplayValue}" /> | ||
+ | </source> | ||
+ | </tab> | ||
+ | </tabs> | ||
+ | <br> | ||
+ | <br> | ||
+ | |||
+ | == Showing Images and Icons == | ||
+ | In UBIK, there are two types of image; | ||
+ | * The thumbnail image assigned to a UBIK object, delivered using the <nowiki>{Binding Icon...}</nowiki> binding, in combination with a ByteToImageConverter. Examples can commonly be found on UBIKChildItem templates. | ||
+ | * Custom image shown with a specific purpose, such as a company logo or icon on a button/UI element. | ||
+ | <br> | ||
+ | |||
+ | ==== Paths as string resources ==== | ||
+ | When using custom images in your UI, it is a good idea not to hardcode path data into your Image control but instead to create a string resource in UBIKThemes that holds the image path, and use this string resource in your Image control. The benefit of the indirect connection between image file and usage is that the "file is in use" issue (sometimes experienced when either manual, or auto-deployment of xamls, tries to change image files when UBIK is running) is avoided this way. | ||
+ | |||
+ | Sample: | ||
+ | <tabs> | ||
+ | <tab name="UWP"> | ||
+ | '''UBIKThemes:''' | ||
+ | <source lang = "xml"><x:String x:Key="MainLogo">ms-appdata:///local/xaml/Images/MainLogo.png</x:String> | ||
+ | </source> | ||
+ | <br> | ||
+ | '''Usage:''' | ||
+ | <source lang = "xml"> | ||
+ | <Image | ||
+ | x:Name="LogoImage" | ||
+ | Height="32" | ||
+ | Stretch="Uniform" | ||
+ | Source="{Binding Source={StaticResource MainLogo}, Converter={StaticResource PathToImageConverter}}" /> | ||
+ | </source> | ||
+ | </tab> | ||
+ | |||
+ | <tab name="Xamarin"> | ||
+ | '''UBIKThemes:''' | ||
+ | <source lang = "xml"> | ||
+ | <x:String x:Key="Logo_Image">IMG_Logo.png</x:String> | ||
+ | </source> | ||
+ | <br> | ||
+ | '''Usage:''' | ||
+ | <source lang = "xml"> | ||
+ | xmlns:customimage="clr-namespace:UBIK.CPL.Controls;assembly=UBIK.CPL" | ||
+ | ... | ||
+ | <customimage:FileImage | ||
+ | HeightRequest="140" | ||
+ | Aspect="AspectFit" | ||
+ | FileName="{StaticResource BorealisLogo_Image}" | ||
+ | FolderName="xaml" /> | ||
+ | </source> | ||
+ | </tab> | ||
+ | </tabs> | ||
+ | <br> | ||
+ | |||
+ | === Icons === | ||
+ | UBIK comes equipped with a collection of icons that can be easily used in your customizing. [[Icon_Font|Here is an indepth explanation on usage]]. | ||
+ | |||
+ | In the case that you require an icon that is not included in our icon font file, there is the possibility to use SVG path data to render your required icon in the UI. | ||
+ | <br> | ||
+ | |||
+ | ==== Custom Icons ==== | ||
+ | Here referring to icons which are not included as standard icons un UBIK. | ||
+ | |||
+ | '''Path data''' is a collection of points, which combined together form a vector image. Vector images, compared to raster images like a PNG or JPG, are scalable, because they are always rendered from path data, and not from a bitmap, which has to be stretched or squished to fit your defined size. | ||
+ | |||
+ | Described below two approaches. The UWP approach involves adding an SVG icon file to your xaml project and render it using an Image control. The Xamarin approach shows how to use svg data directly using a Path control. | ||
+ | <br> | ||
+ | |||
+ | <tabs> | ||
+ | <tab name="UWP"> | ||
+ | <source lang = "xml"> | ||
+ | <Image Width="14" Height="14" Margin="0,0,0,1"> | ||
+ | <Image.Source > | ||
+ | <SvgImageSource UriSource="{StaticResource PP_Issued}" /> | ||
+ | </Image.Source> | ||
+ | </Image> | ||
+ | </tab> | ||
+ | |||
+ | <tab name="Xamarin"> | ||
+ | The first step is to generate path data for your icon. The easiest way is to download the [https://apps.microsoft.com/detail/9wzdncrdxf41?hl=en-US&gl=US| Character Map] tool from Microsoft. This can be used to browse all installed icon files for your icon of choice. Once selected, use Tools > Xaml / Xamarin Forms to show various useful aspects of the icon. In this case, the Path Icon option can be used to generate a Path control that can be pasted directly in your xaml as follows: | ||
+ | <br> | ||
+ | <source lang = "xml"> | ||
+ | <Path Fill="{StaticResource UBIKAccentColor}" Data="F1 M 8.75 1.25 L 18.75 1.25 L 18.75 18.75 L 1.25 18.75 L 1.25 8.75 L 5 8.75 L 5 6.25 L 1.25 6.25 L 1.25 1.25 L 6.25 1.25 L 6.25 5 L 8.75 5 Z M 10 2.5 L 10 5 L 12.5 5 L 12.5 2.5 Z M 2.5 5 L 5 5 L 5 2.5 L 2.5 2.5 Z M 6.25 6.25 L 6.25 8.75 L 8.75 8.75 L 8.75 6.25 Z M 2.5 10 L 2.5 12.5 L 5 12.5 L 5 10 Z M 17.5 17.5 L 17.5 2.5 L 13.75 2.5 L 13.75 6.25 L 10 6.25 L 10 10 L 6.25 10 L 6.25 13.75 L 2.5 13.75 L 2.5 17.5 Z " /> | ||
+ | </source> | ||
+ | <br> | ||
+ | |||
+ | Once you have your Path control, you can customize it as [https://learn.microsoft.com/en-us/previous-versions/xamarin/xamarin-forms/user-interface/shapes/path| documented by Microsoft]. Path data generated using the above method will most likely need a Fill attribute, for example <nowiki>Fill="{StaticResource UBIKAccentColor}"</nowiki>. | ||
+ | |||
+ | {{Hint|More complicated icons will have longer and more complicated paths.}} | ||
+ | </tab> | ||
+ | </tabs> | ||
+ | <br> | ||
+ | <br> | ||
+ | |||
+ | [[Category:Client|XAML Tips]] | ||
+ | [[Category:WinX|XAML Tips]] | ||
+ | [[Category:XAML|XAML Tips]] | ||
+ | [[Category:Xamarin|XAML Tips]] | ||
+ | |||
+ | == FlipView == | ||
+ | |||
+ | === UI virtualization === | ||
When using the FlipView control in your XAML code, it's better to enable [https://docs.microsoft.com/en-us/windows/uwp/debug-test-perf/optimize-gridview-and-listview#ui-virtualization UI virtualization]. The difference in performance gets more obvious as the number of items in the FlipView increases. Here's how to enable it. | When using the FlipView control in your XAML code, it's better to enable [https://docs.microsoft.com/en-us/windows/uwp/debug-test-perf/optimize-gridview-and-listview#ui-virtualization UI virtualization]. The difference in performance gets more obvious as the number of items in the FlipView increases. Here's how to enable it. | ||
Line 185: | Line 695: | ||
</FlipView> | </FlipView> | ||
</source> | </source> | ||
− | |||
VirtualizingStackPanel.VirtualizationMode offers two possibilities: Standard & Recycling. In case you are interested, here are their [https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.virtualizationmode?view=netframework-4.7.2 differences]. | VirtualizingStackPanel.VirtualizationMode offers two possibilities: Standard & Recycling. In case you are interested, here are their [https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.virtualizationmode?view=netframework-4.7.2 differences]. | ||
+ | |||
+ | === Auto saving {{Version/WinXSince|4.6}} === | ||
+ | Unsaved changes on the document (e.g. Annotations) are gonna be saved and committed automatically when flipping the page in the FlipView. | ||
+ | |||
+ | {{Attention|Changes are lost when leaving the page without flipping the document first.}} | ||
+ | |||
+ | {{Version/WinXSince|4.7}} {{Version/XamarinSince|4.7}} If you want to keep the changes when leaving the page by e.g. navigating away without flipping the document first, there is a boolean property called ''AutoSaveDocumentsOnPageClose'' (default value: false) which enables this behavior. It can be activated by adding the property to (or editing it in) the custom UBIKThemes as follows: | ||
+ | <tabs> | ||
+ | <tab name="UWP"> | ||
+ | <source lang = "xml"> | ||
+ | <x:String x:Key="AutoSaveDocumentsOnPageClose">true</x:String> | ||
+ | </source> | ||
+ | </tab> | ||
+ | |||
+ | <tab name="Xamarin"> | ||
+ | <source lang = "xml"> | ||
+ | <x:String x:Key="AutoSaveDocumentsOnPageClose">true</x:String> | ||
+ | </source> | ||
+ | </tab> | ||
+ | </tabs> | ||
[[Category:Client|XAML Tips]] | [[Category:Client|XAML Tips]] | ||
[[Category:WinX|XAML Tips]] | [[Category:WinX|XAML Tips]] | ||
+ | [[Category:XAML|XAML Tips]] | ||
+ | [[Category:Xamarin|XAML Tips]] |
Latest revision as of 12:18, 21 August 2024
Contents
Attachable behaviors
It's quite often that you need to attach behaviors to certain XAML elements. For example, on a Grid, you want to attach a behavior which executes a command upon a Tapped event, or you want to execute a command when a certain property on a UBIK object changes.
Notice that in the following examples, "Interactivity" and "Core" are both namespaces and you have to make sure that they are defined at the root of your XAMLs:
...
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity">
...
</DataTemplate>
Event Triggered
With an EventTriggerBehavior, you can react on changes/events of UI Elements:
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Tapped">
<Core:InvokeCommandAction Command="{Binding NavigateToChildrenCommand}" />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</Grid>
Data Triggered
If you want to react on changes of the underlying data (ViewModel), you can use DataTriggerBehavior instead. The following example, when used in the UBIKSplashArea template, automatically navigates to the root objects once the login process is finished and the user was successfully authenticated:
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding IsLoggedIn}" Value="True">
<Core:InvokeCommandAction Command="{Binding NavigateToRootPageCommand}" />
</Core:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</Grid>
Content creation
Child item creation
To directly create an object on a child of the current object, you can define a Button as follows. The method "Item.IsTypeCreationAllowed" used in the expression gets the uid of the type that should be created below a child, if a child does not allow the creation of that type underneath it, the child will be hidden in the selection dialog. To actually create the object, the "CreateChildItemCommand" needs to be passed a KeyValueList with two parameters: The Parent-key is the UID or the ContentViewModel of the child underneath the object should be created, the Type-key is the type of object which should be created--this should match the uid passed to the "Item.IsTypeCreationAllowed" method.
xmlns:cv="using:UBIK.WinX.UI.CollectionView"
<cv:ListCollectionView x:Key="PlantMapView" Expression="{StaticResource PlantMap}" ItemsSource="{Binding Children.Items}" />
<AppBarButton>
<AppBarButton.Flyout>
<Flyout Placement="Full">
<ListView ItemsSource="{Binding Source={StaticResource PlantMapView}}">
<ListView.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Header}" Command="{Binding CreateChildItemCommand}" x:Name="CreateButton" Tag="{Binding}">
<Button.CommandParameter>
<uc:KeyValueList>
<uc:KeyValueParameter Key="Parent" Value="6D733909-1742-4110-8619-237849BFE453"/>
<uc:KeyValueParameter Key="Type" Value="21fc990a-d064-4bee-8d48-3293351f827a"/>
</uc:KeyValueList>
</Button.CommandParameter>
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Flyout>
</AppBarButton.Flyout>
</AppBarButton>
<cv:ListCollectionView x:Key="PlantMapView" Expression="{StaticResource PlantMap}" ItemsSource="{Binding Children.Items}" />
<AppBarButton>
<AppBarButton.Flyout>
<Flyout Placement="Full">
<ListView ItemsSource="{Binding Source={StaticResource PlantMapView}}">
<ListView.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Header}" Command="{Binding CreateChildItemCommand}" x:Name="CreateButton" Tag="{Binding}">
<Button.CommandParameter>
<uc:KeyValueList>
<uc:KeyValueParameter Key="Parent" Value="{Binding Tag, ElementName=CreateButton}"/>
<uc:KeyValueParameter Key="Type" Value="21fc990a-d064-4bee-8d48-3293351f827a"/>
</uc:KeyValueList>
</Button.CommandParameter>
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Flyout>
</AppBarButton.Flyout>
</AppBarButton>
Additionally, the following optional parameters can be added as well.
- CreateOnly (optional, defaults to false): When set to true, the client will not automatically navigate to the created content, rather automatically save and commit it. If set to true, this overrides the following parameters;
- AutoNavigate (optional, defaults to true): When set to false, the client will not automatically navigate to the created content;
- AutoCommit (optional, defaults to false): When set to true, the change(s) will be saved to the local cache and the database, and then committed to the server.
Creating multiple documents
To upload multiple documents at once, the CreateChildItemsCommand can be used. The list of supported command parameters are similar to those of the CreateChildItemCommand (single item). Except that anything other than AutoNavigate=false and AutoCommit=true do not make sense in multi-creation scenario. Therefore, those parameters are fixed and any received from XAML will be ignored.
xmlns:uc="using:UBIK.WinX.Controls"
Command="{Binding CreateChildItemsCommand}"
Content="Create multiple documents">
<Button.CommandParameter>
<uc:KeyValueList>
<uc:KeyValueParameter Key="Type" Value="6170a068-2314-4444-ad62-0da99769a048" />
</uc:KeyValueList>
</Button.CommandParameter>
</Button>
Disable FilloutCriteria
To enable/disable the automatic filtering of a query based on the ParentObject, there is the possibility to specify EnableFillOutCriteria--if it is not set, it defaults to false. Additionaly "SkipDialog" can be set to true, to not display a dialog.
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Tapped">
<Core:InvokeCommandAction Command="{Binding ElementName=ChildAreaGrid, Path=DataContext.AddTemplatableDataCommand}" >
<Core:InvokeCommandAction.CommandParameter>
<uc:KeyValueList>
<uc:KeyValueParameter Key="Uid" Value="{Binding Tag,ElementName=selectionGrid}"/>
<uc:KeyValueParameter Key="EnableFillOutCriteria" Value="false"/>
<uc:KeyValueParameter Key="SkipDialog" Value="false"/>
</uc:KeyValueList>
</Core:InvokeCommandAction.CommandParameter>
</Core:InvokeCommandAction>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</Grid>
Hotspotting
To use a binding in the KeyValueParameter, it has to be applied like in the example provided here: KeyValueList |
The hotspotting command is used for hotspotting as well as for annotating, to configure the button for hotspotting, the commandparameter "Mode" should be set to "HotSpotting", for annotating the "Mode" should be "Annotate". The parameter commit is optional, if set to true, the changes get automatically persisted when leaving the editing mode.
IsChecked="{Binding EditingAnnotation, Mode=TwoWay}"
IsEnabled="{Binding IsAnnotatable}"
Command="{Binding HotSpottingCommand}">
<AppBarToggleButton.CommandParameter>
<uc:KeyValueList>
<uc:KeyValueParameter Key="Mode" Value="Annotate"/>
<uc:KeyValueParameter Key="Commit" Value="true"/>
</uc:KeyValueList>
</AppBarToggleButton.CommandParameter>
</AppBarToggleButton>
Remember scroll positions of list views
Version 3.7 & later
Starting from this version,
- The precision of scroll position remembering is improved(by pixel offsets instead of by items);
- It also works for other scrollable lists (instead of just for content object lists).
To enable this feature, you should make sure the following.
- The SelectionBoundListView is used instead of the standard ListView. Its UBIK® namespace is
UBIK.WinX.Controls
; - The SelectionBoundListView's
RememberScrollPosition
property is not set to "false"; (It's "true" by default.) - The SelectionBoundListView's
x:Name
property value is unique.
Version 3.6
The UBIK-Client does include a function to remember the position in a list (ListView) when navigating away from it. This function is only available when the list (ListView) has a unique name as a property (x:Name). When browsing back to the previously visited list UBIK scrolls back to the last position. The function does not save scroll positions over different sessions. Implementing the function to remember the scroll position in a ListView one has to consider that the list elements (Children) could depend on a other UI-element. If the list elements do depend on a other UI-elemente, this element has to be created above the ListView in the XAML.
...
<uc:SelectionBoundListView x:Name="ChildListView">
<Interactivity:Interaction.Behaviors>
<behaviors:FirstVisibleItemPersistenceBehavior FirstVisibleItems="{Binding ScrollItems}" />
</Interactivity:Interaction.Behaviors>
</uc:SelectionBoundListView>
</DataTemplate>
MultiBinding
Very often we want to display some UI elements (e.g. a Grid) depending on whether multiple criteria are met. It's much easier to achieve this by using a MultiBindingBehavior like the following.
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:behaviors="using:UBIK.WinX.Behaviors">
...
<Grid>
<Interactivity:Interaction.Behaviors>
<behaviors:MultiBindingBehavior Converter="{StaticResource VisLogicAndConverter}" PropertyName="Visibility">
<behaviors:MultiBindingItem Value="{Binding MassEditViewModel, Converter={StaticResource NullToVisConverter}}" />
<behaviors:MultiBindingItem Value="{Binding Documents.Items.Count, Converter={StaticResource ItemCountToVisConverter}}" />
</behaviors:MultiBindingBehavior>
</Interactivity:Interaction.Behaviors>
</Grid>
</DataTemplate>
The behavior makes sure the container Grid is set to Visibile only if the mass editing mode is not turned on (MassEditViewModel is null) and the context object has child document(s) (Documents.Items.Count is greater than 0. You can combine any number of binding results (MultiBindingItem) using the VisLogicAndConverter (the name should be self explanatory).
Other Commands
InvokeOnItemsCommand
Available on all ListViewModels, this command allows executing a specified command on a collection of list items. It can be used in combination with features such as mass editing and expression based collection filtering. Examples for both combinations are provided below.
The command specified through the "Command" parameter is executed on list items and, therefore, must be available in the list item contexts (view models). If in doubt, the developer mode can be used to inspect if a command is available in a certain context. |
Invoke on selected items
To use a binding in the KeyValueParameter, it has to be applied like in the example provided here: KeyValueList |
This example demonstrates how you can use the mass editing feature to select certain objects from the child list and then execute the SetPropertyValueCommand for those selected.
- The example code assumes that the child objects have an editable property called "VALUE" and tries to set 50 as their value;
- You should insert the following code snippet into the default UBIKChildArea template;
- If the parameter "SelectedItemsOnly" is missed or set to "False", the command will be executed on all child items;
- To enable selection, click on the "Mass Edit" button below the property list.
UWP
xmlns:example="using:UBIK.WinX.Controls"
Command="{Binding Children.InvokeOnItemsCommand}"
Content="Set to 50%">
<Button.CommandParameter>
<example:KeyValueList>
<example:KeyValueParameter Key="Command" Value="SetPropertyValueCommand" />
<example:KeyValueParameter Key="SelectedItemsOnly" Value="False" />
<example:KeyValueParameter Key="PropertyName" Value="VALUE" />
<example:KeyValueParameter Key="PropertyValue">
<example:KeyValueParameter.Value>
<x:Double>50</x:Double>
</example:KeyValueParameter.Value>
</example:KeyValueParameter>
</example:KeyValueList>
</Button.CommandParameter>
</Button>
Xamarin
xmlns:example="clr-namespace:UBIK.CPL.Classes;assembly=UBIK.CPL"
Command="{Binding Children.InvokeOnItemsCommand}"
Text="Set to 50%">
<Button.CommandParameter>
<example:KeyValueList>
<example:KeyValueParameter Key="Command" Value="SetPropertyValueCommand" />
<example:KeyValueParameter Key="SelectedItemsOnly" Value="False" />
<example:KeyValueParameter Key="PropertyName" Value="VALUE" />
<example:KeyValueParameter Key="PropertyValue">
<example:KeyValueParameter.Value>
<x:Double>50</x:Double>
</example:KeyValueParameter.Value>
</example:KeyValueParameter>
</example:KeyValueList>
</Button.CommandParameter>
</Button>
Invoke on filtered results
To use a binding in the KeyValueParameter, it has to be applied like in the example provided here: KeyValueList |
- First, you need to setup a filtered list
- UWP: Setup a ListCollectionView in the Resources section of a UI element (e.g. Grid). This list is only available/visible within that UI element (the Grid in this case).
- Xamarin: Setup a String with a filtering expression & a SfDataSourceExt in the ResourceDictionary of the ContentView. For the Expression property of the SfDataSourceExt refer to the created expression String.
- The ItemsSource uses Children.Items. Use the developer mode if necessary to find out if this is available where you intend to define the list;
- The example expression filters for any items that don't contain the text "EXAMPLE" in their Title texts. You can filter differently by altering the expression.
UWP
<Grid.Resources>
<CV:ListCollectionView
x:Key="Filtered"
Expression="!Item.Title.Contains("EXAMPLE")"
ItemsSource="{Binding Children.Items}" />
</Grid.Resources>
...
</Grid>
Xamarin
xmlns:controls="clr-namespace:UBIK.CPL.Controls;assembly=UBIK.CPL"
...>
<ContentView.Resources>
<ResourceDictionary>
<x:String x:Key="Expresssion">!Item.Title.Contains("EXAMLPLE")</x:String>
<controls:SfDataSourceExt x:Key="Filtered" Expression="{StaticResource Expresssion}" ItemsSource="{Binding Children.Items}" />
</ResourceDictionary>
</ContentView.Resources>
</ContentView>
With the filtered list configured, you can then insert the following code snippet to execute the SetPropertyValueCommand for the filtered result items.
- The example code assumes that the child objects have an editable property called "VALUE" and tries to set 50 as their value;
- The "Filtered" refers to the ListCollectionView (UWP) or SfDataSourceExt (Xamarin) configured above.
UWP
xmlns:example="using:UBIK.WinX.Controls"
Command="{Binding Source={StaticResource Filtered}, Path=ListViewModel.InvokeOnItemsCommand}"
Icon="AllApps"
Label="Set to 50"
Style="{ThemeResource UBIKActionAppBarButton}">
<AppBarButton.CommandParameter>
<example:KeyValueList>
<example:KeyValueParameter Key="Command" Value="SetPropertyValueCommand" />
<example:KeyValueParameter Key="PropertyName" Value="VALUE" />
<example:KeyValueParameter Key="PropertyValue" Value="50" />
</example:KeyValueList>
</AppBarButton.CommandParameter>
</AppBarButton>
Xamarin
xmlns:example="clr-namespace:UBIK.CPL.Classes;assembly=UBIK.CPL"
Command="{Binding Source={StaticResource Filtered}, Path=ListViewModel.InvokeOnItemsCommand}"
Text="Set to 50">
<Button.CommandParameter>
<example:KeyValueList>
<example:KeyValueParameter Key="Command" Value="SetPropertyValueCommand" />
<example:KeyValueParameter Key="PropertyName" Value="VALUE" />
<example:KeyValueParameter Key="PropertyValue" Value="50" />
</example:KeyValueList>
</Button.CommandParameter>
</Button>
The binding ListViewModel.InvokeOnItemsCommand should be updated to BulkOperation.InvokeOnItemsCommand starting from version 4.3. |
Support for old styled commands
Some old commands might not support KeyValueLists as parameters. In that case, just define the parameter value under the "CommandParameter" key, e.g.
This single value is then passed as the command parameter instead of the entire KeyValueList.
SetPropertyValueCommand
To use a binding in the KeyValueParameter, it has to be applied like in the example provided here: KeyValueList |
This command existed before but was implemented differently. In the newer version(s), it is improved to provide customizers more control over the things that happen during/after the property value changes. The available command parameters are:
- PropertyName: the name of the property to set a new value to;
- PropertyValue: the value to be set to the above mentioned property;
- OnlyForUnvalidated (optional, defaults to false): When set to true, the value will only be set if the property is not yet validated;
- AutoSave (optional, defaults to false): When set to true, the change(s) will be saved to the local cache and database;
- AutoCommit (optional, defaults to false): When set to true, the change(s) will be committed to the server.
There's no way to commit changes without saving them locally first. Therefore, the "AutoSave" parameter will be ignored when "AutoCommit" is set to true. |
Here's an example of the command usage. It tries to set the property called "VALUE" to a double value 50 regardless of its current state and then automatically save and commit the change.
xmlns:example="using:UBIK.WinX.Controls"
Command="{Binding SetPropertyValueCommand}"
Icon="Edit"
Label="Set to 50%">
<AppBarButton.CommandParameter>
<example:KeyValueList>
<example:KeyValueParameter Key="PropertyName" Value="VALUE" />
<example:KeyValueParameter Key="PropertyValue">
<example:KeyValueParameter.Value>
<x:Double>50</x:Double>
</example:KeyValueParameter.Value>
</example:KeyValueParameter>
<example:KeyValueParameter Key="OnlyForUnvalidated" Value="false" />
<example:KeyValueParameter Key="AutoSave" Value="true" />
<example:KeyValueParameter Key="AutoCommit" Value="true" />
</example:KeyValueList>
</AppBarButton.CommandParameter>
</AppBarButton>
SaveAndCommitCommand
With the SaveAndCommitCommand it is possible to save and commit unsaved changes on a ContentViewModel.
- ForceCommit CommandParameter (optional, defaults to false): Normally when the App is in Online mode, changes are automatically committed when saved. This is not the case when the App is in Manual mode. Setting the ForceCommit parameter to true makes it possible to commit the changes when saved in Manual mode.
- PropertyNameToSave CommandParameter (optional, defaults to null): Delivers the Property Name as String of a specific Property that should be saved. E.g. when called via PropertyViewModel.ResetCommand or PropertyViewModel.DeleteCommand, the PropertyNameToSave parameter is used to only apply the SaveAndCommitCommand on the related PropertyViewModel called from, and not on other unsaved changes on this ContentViewModel.
UWP
xmlns:example="using:UBIK.WinX.Controls"
Command="{Binding SaveAndCommitCommand}">
<Button.CommandParameter>
<example:KeyValueList>
<example:KeyValueParameter Key="ForceCommit" Value="True" />
</example:KeyValueList>
</Button.CommandParameter>
</Button>
Xamarin
xmlns:example="using:clr-namespace:UBIK.CPL.Classes;assembly=UBIK.CPL"
Command="{Binding SaveAndCommitCommand}">
<Button.CommandParameter>
<example:KeyValueList>
<example:KeyValueParameter Key="ForceCommit" Value="True" />
</example:KeyValueList>
</Button.CommandParameter>
</Button>
DisplayViewCommand
This command can be used to display cutom views.
TeachInCommand
With the TeachInCommand you're allowed to set your device's current location ("teach-in", "TeachIn") as the value of the context object's geo property. This command is available in both ContentViewModel and PropertyViewModel.
- ContentViewModel.TeachInCommand: If possible, sets the current location of the device as the value of the context object's geo property. Saves and commits the change;
- PropertyViewModel.TeachInCommand: If possible, sets the current location of the device as the value of the current property if it's a geo property (not necessarily the geo property). Addtionally supports a boolean command parameter:
- False (default): The change is not automatically saved.
- True: The change is saved.
Make sure you use the correct binding path for your command depending on your current context view model. E.g., if the context view model is already the ContentViewModel then your binding path should simply be TeachInCommand. You can use the developer mode to find out the current view model in a view. |
UpdateArbitraryObjectCommand
The "UpdateArbitraryObjectCommand" is responsible for updating an arbitrary object based on a set of provided parameters. The command is accessible in the AppStatusViewModel (as ViewModel.AppStatus).
The available command parameters are:
- Uid (Mandatory): UID of the object to be updated;
- UpdateChildDepth (Optional): Child depth/level to update (defaults to 1);
- UpdateParentDepth (Optional): Parent depth/level to update (defaults to 0);
- UpdateIgnoreExpiry (Optional): Ignore update expiry (defaults to false);
Note that if you set the UpdateChildDepth property to "-1" you are also able to update a whole branch with this command. |
Here is an example of the command usage:
UWP
xmlns:uc="using:UBIK.WinX.Controls"
Command="{Binding UpdateArbitraryObjectCommand}"
Content="Update Arbitrary Object">
<Button.CommandParameter>
<uc:KeyValueList>
<uc:KeyValueParameter Key="Uid" Value="...valid UID..." />
<uc:KeyValueParameter Key="UpdateChildDepth" Value="2" />
<uc:KeyValueParameter Key="UpdateParentDepth" Value="0" />
<uc:KeyValueParameter Key="UpdateIgnoreExpiry" Value="true" />
</uc:KeyValueList>
</Button.CommandParameter>
</Button>
Xamarin
xmlns:uc="using:clr-namespace:UBIK.CPL.Classes;assembly=UBIK.CPL"
Command="{Binding UpdateArbitraryObjectCommand}"
Content="Update Arbitrary Object">
<Button.CommandParameter>
<uc:KeyValueList>
<uc:KeyValueParameter Key="Uid" Value="...valid UID..." />
<uc:KeyValueParameter Key="UpdateChildDepth" Value="2" />
<uc:KeyValueParameter Key="UpdateParentDepth" Value="0" />
<uc:KeyValueParameter Key="UpdateIgnoreExpiry" Value="true" />
</uc:KeyValueList>
</Button.CommandParameter>
</Button>
Access to an arbitrary object
With the ObjectByUID feature it is possible to access any local arbitrary object by its UID and, for example, display a value of it. It can be accessed from ContentViewModel, AuthenticationViewModel, and RootPageViewModel levels.
To display a string of e.g. a property of an arbitrary object from ContentViewModel, AuthenticationViewModel & RootPageViewModel, the following syntax can be used in related XAMLs:
UWP
Xamarin
For Property Dialogs the CallingViewModel prefix is needed to access an arbitrary object:
UWP
Xamarin
Showing Images and Icons
In UBIK, there are two types of image;
- The thumbnail image assigned to a UBIK object, delivered using the {Binding Icon...} binding, in combination with a ByteToImageConverter. Examples can commonly be found on UBIKChildItem templates.
- Custom image shown with a specific purpose, such as a company logo or icon on a button/UI element.
Paths as string resources
When using custom images in your UI, it is a good idea not to hardcode path data into your Image control but instead to create a string resource in UBIKThemes that holds the image path, and use this string resource in your Image control. The benefit of the indirect connection between image file and usage is that the "file is in use" issue (sometimes experienced when either manual, or auto-deployment of xamls, tries to change image files when UBIK is running) is avoided this way.
Sample:
UWP
UBIKThemes:
Usage:
x:Name="LogoImage"
Height="32"
Stretch="Uniform"
Source="{Binding Source={StaticResource MainLogo}, Converter={StaticResource PathToImageConverter}}" />
Xamarin
UBIKThemes:
Usage:
...
<customimage:FileImage
HeightRequest="140"
Aspect="AspectFit"
FileName="{StaticResource BorealisLogo_Image}"
FolderName="xaml" />
Icons
UBIK comes equipped with a collection of icons that can be easily used in your customizing. Here is an indepth explanation on usage.
In the case that you require an icon that is not included in our icon font file, there is the possibility to use SVG path data to render your required icon in the UI.
Custom Icons
Here referring to icons which are not included as standard icons un UBIK.
Path data is a collection of points, which combined together form a vector image. Vector images, compared to raster images like a PNG or JPG, are scalable, because they are always rendered from path data, and not from a bitmap, which has to be stretched or squished to fit your defined size.
Described below two approaches. The UWP approach involves adding an SVG icon file to your xaml project and render it using an Image control. The Xamarin approach shows how to use svg data directly using a Path control.
UWP
<Image Width="14" Height="14" Margin="0,0,0,1">
<Image.Source >
<SvgImageSource UriSource="{StaticResource PP_Issued}" />
</Image.Source>
</Image>
Xamarin
The first step is to generate path data for your icon. The easiest way is to download the Character Map tool from Microsoft. This can be used to browse all installed icon files for your icon of choice. Once selected, use Tools > Xaml / Xamarin Forms to show various useful aspects of the icon. In this case, the Path Icon option can be used to generate a Path control that can be pasted directly in your xaml as follows:
Once you have your Path control, you can customize it as documented by Microsoft. Path data generated using the above method will most likely need a Fill attribute, for example Fill="{StaticResource UBIKAccentColor}".
FlipView
UI virtualization
When using the FlipView control in your XAML code, it's better to enable UI virtualization. The difference in performance gets more obvious as the number of items in the FlipView increases. Here's how to enable it.
...
VirtualizingStackPanel.VirtualizationMode="Standard">
<Flipview.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</Flipview.ItemsPanel>
</FlipView>
VirtualizingStackPanel.VirtualizationMode offers two possibilities: Standard & Recycling. In case you are interested, here are their differences.
Auto saving
Unsaved changes on the document (e.g. Annotations) are gonna be saved and committed automatically when flipping the page in the FlipView.
If you want to keep the changes when leaving the page by e.g. navigating away without flipping the document first, there is a boolean property called AutoSaveDocumentsOnPageClose (default value: false) which enables this behavior. It can be activated by adding the property to (or editing it in) the custom UBIKThemes as follows: