7,303 bytes added,
Friday at 11:44 = UBIK Traits (Client) =
'''UBIK Traits''' provide the ability to define a dynamic list of lightweight properties for individual instances (objects). Unlike traditional UBIK Properties, which are rigidly bound to a MetaClass, instances of the same entity can possess 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.
{{Attention|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 <code>ContentViewModel</code> provides several dedicated accessors and collections.
=== 1. ValueAccessors (Recommended for Read/Write) ===
The <code>ValueAccessors</code> 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 <code>null</code>.
=== 2. TraitByName (Traits Only) ===
A dedicated collection (<code>ObservableTraitDictionary</code>) that exclusively loads and initializes traits. Unlike the <code>ValueAccessors</code>, 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 <code>TraitViewModel</code> or <code>PropertyViewModel</code>.
* '''Usage:''' For pure display purposes or evaluations
----
== Commands (Set & Create Values) ==
=== SetValueCommand ===
This command on the <code>ContentViewModel</code> 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 <code>TraitViewModel</code> is created and added to the UBIKContent.
----
== Customizing / UI Integration (XAML Examples) ==
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. Here are real-world code examples to guide you:
=== 1. Pure Display of All Traits (List View) ===
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| With that you only bind on DataModel level (changes on viewmodel level are only visible after saving).}}
<syntaxhighlight lang="xml">
<controls:SfListViewExt ItemsSource="{Binding Content.Traits}">
<controls:SfListViewExt.ItemTemplate>
<DataTemplate>
<Border Padding="10,8" BackgroundColor="#FAFAFA" Stroke="#E0E0E0" StrokeShape="RoundRectangle 8">
<Grid ColumnDefinitions="0.4*, 0.6*">
<Label Grid.Column="0" FontAttributes="Bold" Text="{Binding Name}" VerticalTextAlignment="Center" />
<Label Grid.Column="1" Text="{Binding Value, TargetNullValue='Not found'}" TextColor="#555555" VerticalTextAlignment="Center" />
</Grid>
</Border>
</DataTemplate>
</controls:SfListViewExt.ItemTemplate>
</controls:SfListViewExt>
</syntaxhighlight>
=== 2. Edit a Single Trait or Property (via ValueAccessors) ===
To dynamically query and edit a specific trait, use the <code>EvalExpression</code> with the <code>ValueAccessors</code> context. The <code>TwoWay</code> binding ensures that changes are written directly back to the ViewModel.
<syntaxhighlight lang="xml">
<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" Placeholder="Enter name..." />
<Entry x:Name="S2ValueInput" Text="{Binding Result.Value, Source={x:Reference EvalS2}, Mode=TwoWay, FallbackValue='Not found'}" />
</syntaxhighlight>
=== 3. Delete a Trait ===
Deleting a trait does not require a dedicated command. Instead, it uses an event behavior to directly invoke the <code>Delete</code> method on the evaluator's result.
<syntaxhighlight lang="xml">
<Button Text="Delete" BackgroundColor="#D32F2F" TextColor="White">
<Button.Behaviors>
<behaviors:EventHandlerBehavior EventName="Clicked">
<behaviors:InvokeMethodAction TargetObject="{Binding Result, Source={x:Reference EvalS2}}" MethodName="Delete" />
</behaviors:EventHandlerBehavior>
</Button.Behaviors>
</Button>
</syntaxhighlight>
=== 4. Create or Overwrite 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> is used. A <code>KeyValueList</code> must be passed to this command.
<syntaxhighlight lang="xml">
<Grid ColumnDefinitions="*, Auto" ColumnSpacing="10">
<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>
</syntaxhighlight>
=== 5. Edit Specific Datatypes (e.g., DatePicker) ===
Traits store actual underlying datatypes (such as <code>DateTime</code>). This means you can bind regular UI controls like a <code>DatePicker</code> directly to the result of the <code>EvalExpression</code>.
<syntaxhighlight lang="xml">
<controls:EvalExpression x:Name="EvalDateTime" Context="{Binding}" Expression="Context.ValueAccessors[P0]">
<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>
</syntaxhighlight>
----