Last modified on 24 April 2026, at 12:01

Traits

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.

IC Attention.pngThis 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:

  1. Trait Lookup: First attempts to resolve the value via a trait with the specified name.
  2. Property Fallback: If no trait is found, it queries a regular UBIK Property with that name.
  3. Default: If neither exists, it returns null.

2. TraitByName (Traits Only)

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 TraitViewModel 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 EvalExpression or SfListViewExt 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 Content.Traits. Here, it is combined with the Syncfusion ListView (SfListViewExt):

IC Attention.png With that you only bind on DataModel level (changes on viewmodel level are only visible after saving).
<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>

2. Edit a Single Trait or Property (via ValueAccessors)

To dynamically query and edit a specific trait, use the EvalExpression with the ValueAccessors context. 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" Placeholder="Enter name..." />

<Entry x:Name="S2ValueInput" Text="{Binding Result.Value, Source={x:Reference EvalS2}, Mode=TwoWay, FallbackValue='Not found'}" />

3. Delete a Trait

Deleting a trait does not require a dedicated command. Instead, it uses an event behavior to directly invoke the Delete method on the evaluator's result.

<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>

4. Create or Overwrite a Trait (via SetValueCommand)

To create traits entirely from scratch (or explicitly overwrite an existing value), the SetValueCommand of the ContentViewModel is used. A KeyValueList must be passed to this command.

<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>

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: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>