Difference between revisions of "Traits"
(→Customizing / UI Integration (XAML Examples)) |
(→XAML Customizing / UI Integration) |
||
| Line 46: | Line 46: | ||
== XAML Customizing / UI Integration == | == XAML Customizing / UI Integration == | ||
| − | To display traits in custom XAML templates, make them editable, or create new ones, standard {{UBIK}} controls like <code>EvalExpression</code> or <code>SfListViewExt</code> are used. | + | To display traits in custom XAML templates, make them editable, or create new ones, standard {{UBIK}} controls like <code>EvalExpression</code> or <code>SfListViewExt</code> are used. |
| − | + | ||
| − | === 1. | + | === 1.Displaying all Traits in a List View (read-only) === |
| − | If you simply want to display all traits of an object, you can bind directly to <code>Content.Traits</code>. Here | + | If you simply want to display all traits of an object, you can bind directly to <code>Content.Traits</code>. Here it is combined with the Syncfusion ListView (<code>SfListViewExt</code>): |
| − | {{Attention| | + | {{Attention| Bindings persist only on DataModel level which means changes on ViewModel level are only visible after saving.}} |
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
| + | xmlns:controls="clr-namespace:UBIK.MAUI.Controls;assembly=UBIK.MAUI" | ||
| + | |||
<controls:SfListViewExt ItemsSource="{Binding Content.Traits}"> | <controls:SfListViewExt ItemsSource="{Binding Content.Traits}"> | ||
<controls:SfListViewExt.ItemTemplate> | <controls:SfListViewExt.ItemTemplate> | ||
<DataTemplate> | <DataTemplate> | ||
| − | |||
<Grid ColumnDefinitions="0.4*, 0.6*"> | <Grid ColumnDefinitions="0.4*, 0.6*"> | ||
| − | <Label Grid.Column="0 | + | <Label Grid.Column="0" Text="{Binding Name}" /> |
| − | <Label Grid.Column="1" Text="{Binding Value | + | <Label Grid.Column="1" Text="{Binding Value}" /> |
</Grid> | </Grid> | ||
| − | |||
</DataTemplate> | </DataTemplate> | ||
</controls:SfListViewExt.ItemTemplate> | </controls:SfListViewExt.ItemTemplate> | ||
| Line 66: | Line 66: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| − | === 2. | + | === 2. Editing a single Trait or Property via ValueAccessors === |
| − | To dynamically query and edit a specific trait, | + | To dynamically query and edit a specific trait, an <code>EvalExpression</code> with the <code>ValueAccessors</code> Context should be used. The <code>TwoWay</code> binding ensures that changes are written directly back to the ViewModel. |
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
| + | xmlns:controls="clr-namespace:UBIK.MAUI.Controls;assembly=UBIK.MAUI" | ||
| + | |||
<controls:EvalExpression x:Name="EvalS2" Context="{Binding ValueAccessors}" Expression="Context[P0]"> | <controls:EvalExpression x:Name="EvalS2" Context="{Binding ValueAccessors}" Expression="Context[P0]"> | ||
<controls:EvalExpressionParameter Name="P0" Value="{Binding Path=Text, Source={x:Reference S2NameInput}}" /> | <controls:EvalExpressionParameter Name="P0" Value="{Binding Path=Text, Source={x:Reference S2NameInput}}" /> | ||
</controls:EvalExpression> | </controls:EvalExpression> | ||
| − | <Entry x:Name="S2NameInput | + | <Entry x:Name="S2NameInput" /> |
| − | <Entry x:Name="S2ValueInput" Text="{Binding Result.Value, Source={x:Reference EvalS2}, Mode=TwoWay | + | <Entry x:Name="S2ValueInput" Text="{Binding Result.Value, Source={x:Reference EvalS2}, Mode=TwoWay}" /> |
</syntaxhighlight> | </syntaxhighlight> | ||
| − | === 3. | + | === 3. Deleting a Trait === |
| − | Deleting a trait does not require a dedicated command. Instead | + | Deleting a trait does not require a dedicated command. Instead an event behavior can be used to directly invoke the <code>Delete</code> method on the evaluator's result.. |
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
| − | <Button Text="Delete | + | xmlns:behaviors="clr-namespace:UBIK.MAUI.Behaviors;assembly=UBIK.MAUI" |
| + | |||
| + | <Button Text="Delete"> | ||
<Button.Behaviors> | <Button.Behaviors> | ||
<behaviors:EventHandlerBehavior EventName="Clicked"> | <behaviors:EventHandlerBehavior EventName="Clicked"> | ||
| Line 92: | Line 96: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| − | === 4. | + | === 4. Creating or overwriting a Trait via SetValueCommand === |
| − | To create traits entirely from scratch (or explicitly overwrite an existing value), the <code>SetValueCommand</code> of the <code>ContentViewModel</code> | + | To create traits entirely from scratch (or to explicitly overwrite an existing value), the <code>SetValueCommand</code> of the <code>ContentViewModel</code> should be used. A <code>KeyValueList</code> must be passed to this Command. |
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
Revision as of 09:39, 27 April 2026
Contents
UBIK® Traits (Client)
UBIK® Traits provide the ability to define a dynamic list of lightweight properties for individual instances (UBIK® objects). Unlike traditional UBIK® Properties, which are rigidly bound to a MetaClass, instances of the same entity can contain a different list of traits.
This feature is particularly useful for data that only becomes known at runtime or varies significantly from instance to instance.
| This feature must be used wisely, too many traits could impact the performance. Traits do not replace properties. |
ViewModel Architecture & Data Access
To work with traits in the UI (XAML), the ContentViewModel provides several dedicated accessors and collections.
1. ValueAccessors (Recommended for Read/Write)
The ValueAccessors acts as a combined dynamic value resolver. It is the preferred way to read or edit values in the UI because of its built-in fallback logic:
- Trait Lookup: First attempts to resolve the value via a trait with the specified name.
- Property Fallback: If no trait is found, it queries a regular UBIK® Property with that name.
- Default: If neither exists, it returns
null.
2. TraitByName (Traits Only)
TraitByName is a dedicated collection (ObservableTraitDictionary) that exclusively loads and initializes traits. Unlike the ValueAccessors, this does not fall back to regular properties.
- Usage: When you explicitly want to query only traits (e.g., read-only display in the UI).
3. Values (Raw Data)
This is a combined getter that returns the raw value directly from the dictionary, instead of providing a complex TraitViewModel or PropertyViewModel.
- Usage: For pure display purposes or evaluations.
Commands (Set & Create Values)
SetValueCommand
This command on the ContentViewModel orchestrates value assignments and handles the creation of new traits if necessary.
- If the trait exists: The value will be overwritten.
- If a property exists: The property's value will be overwritten (if it is not locked/read-only).
- If neither exists: A new
TraitViewModelis created and added to the UBIK® content.
XAML Customizing / UI Integration
To display traits in custom XAML templates, make them editable, or create new ones, standard UBIK® controls like EvalExpression or SfListViewExt are used.
1.Displaying all Traits in a List View (read-only)
If you simply want to display all traits of an object, you can bind directly to Content.Traits. Here it is combined with the Syncfusion ListView (SfListViewExt):
| Bindings persist only on DataModel level which means changes on ViewModel level are only visible after saving. |
<controls:SfListViewExt ItemsSource="{Binding Content.Traits}">
<controls:SfListViewExt.ItemTemplate>
<DataTemplate>
<Grid ColumnDefinitions="0.4*, 0.6*">
<Label Grid.Column="0" Text="{Binding Name}" />
<Label Grid.Column="1" Text="{Binding Value}" />
</Grid>
</DataTemplate>
</controls:SfListViewExt.ItemTemplate>
</controls:SfListViewExt>
2. Editing a single Trait or Property via ValueAccessors
To dynamically query and edit a specific trait, an EvalExpression with the ValueAccessors Context should be used. The TwoWay binding ensures that changes are written directly back to the ViewModel.
<controls:EvalExpression x:Name="EvalS2" Context="{Binding ValueAccessors}" Expression="Context[P0]">
<controls:EvalExpressionParameter Name="P0" Value="{Binding Path=Text, Source={x:Reference S2NameInput}}" />
</controls:EvalExpression>
<Entry x:Name="S2NameInput" />
<Entry x:Name="S2ValueInput" Text="{Binding Result.Value, Source={x:Reference EvalS2}, Mode=TwoWay}" />
3. Deleting a Trait
Deleting a trait does not require a dedicated command. Instead an event behavior can be used to directly invoke the Delete method on the evaluator's result..
<Button Text="Delete">
<Button.Behaviors>
<behaviors:EventHandlerBehavior EventName="Clicked">
<behaviors:InvokeMethodAction TargetObject="{Binding Result, Source={x:Reference EvalS2}}" MethodName="Delete" />
</behaviors:EventHandlerBehavior>
</Button.Behaviors>
</Button>
4. Creating or overwriting a Trait via SetValueCommand
To create traits entirely from scratch (or to explicitly overwrite an existing value), the SetValueCommand of the ContentViewModel should be used. A KeyValueList must be passed to this Command.
<Entry x:Name="S4NameInput" Placeholder="Name of the (new) trait..." />
<Entry x:Name="S4ValueInput" Grid.Column="0" Placeholder="Enter value to set..." />
<Button Grid.Column="1" Command="{Binding SetValueCommand}" Text="Set">
<Button.CommandParameter>
<classes:KeyValueList>
<classes:KeyValueParameter Key="PropertyName" Value="{Binding Text, Source={x:Reference S4NameInput}}" />
<classes:KeyValueParameter Key="PropertyValue" Value="{Binding Text, Source={x:Reference S4ValueInput}}" />
</classes:KeyValueList>
</Button.CommandParameter>
</Button>
</Grid>
5. Edit Specific Datatypes (e.g., DatePicker)
Traits store actual underlying datatypes (such as DateTime). This means you can bind regular UI controls like a DatePicker directly to the result of the EvalExpression.
<controls:EvalExpressionParameter Name="P0" Value="{Binding Path=Text, Source={x:Reference DateTraitNameInput}}" />
</controls:EvalExpression>
<Entry x:Name="DateTraitNameInput" Text="TRAIT_DATETIME" />
<DatePicker x:Name="DateTestPicker" Date="{Binding Result.Value, Source={x:Reference EvalDateTime}}" Format="dd.MM.yyyy" />
<Button Command="{Binding SetValueCommand}" Text="Set">
<Button.CommandParameter>
<classes:KeyValueList>
<classes:KeyValueParameter Key="PropertyName" Value="{Binding Text, Source={x:Reference DateTraitNameInput}}" />
<classes:KeyValueParameter Key="PropertyValue" Value="{Binding Date, Source={x:Reference DateTestPicker}}" />
</classes:KeyValueList>
</Button.CommandParameter>
</Button>
