Jump to: navigation, search

Difference between revisions of "Traits"


(3. Values (Raw Data))
 
(13 intermediate revisions by the same user not shown)
Line 1: Line 1:
= {{UBIK}} Traits (Client) =
+
= Traits =
  
'''{{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.  
+
'''{{UBIK}} Traits''' provide the ability to define a dynamic list of properties for individual instances ({{UBIK}} objects). Unlike traditional {{UBIK}} Properties, which are rigidly bound to a [[MetaClass|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 is particularly useful for data that only becomes known at runtime or varies significantly from instance to instance. Please note that traits do not use lazy loading, making them act rather "heavy weight" from a user's perspective.
 +
 
 +
Supported types:
 +
* int
 +
* double
 +
* string
 +
* bool
 +
* date time
  
 
{{Attention|This feature must be used wisely, too many traits could impact the performance. Traits do not replace properties.}}
 
{{Attention|This feature must be used wisely, too many traits could impact the performance. Traits do not replace properties.}}
Line 10: Line 17:
 
To work with traits in the UI (XAML), the <code>ContentViewModel</code> provides several dedicated accessors and collections.  
 
To work with traits in the UI (XAML), the <code>ContentViewModel</code> provides several dedicated accessors and collections.  
  
=== 1. ValueAccessors (Recommended for Read/Write) ===
+
=== 1. ValueAccessors (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:
+
The <code>ValueAccessors</code> acts as a combined dynamic value resolver. It provides a built-in fallback logic:
 
# '''Trait Lookup:''' First attempts to resolve the value via a trait with the specified name.
 
# '''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.
+
# '''Property Fallback:''' If no trait is found, it queries a regular {{UBIK}} Property with that name (see [[XAML#PropertyByName.5BMP_PROPERTY.5D|PropertyByName]]).
 
# '''Default:''' If neither exists, it returns <code>null</code>.
 
# '''Default:''' If neither exists, it returns <code>null</code>.
 +
 +
{{Attention|'''Caution:''' Be careful when using ValueAccessors. If you mistype a property name in XAML, you might not notice the error immediately and spend unnecessary time debugging. If you know you strictly need properties, use standard property bindings.}}
 +
 +
'''XAML Example (Reading a value):'''
 +
<syntaxhighlight lang="xml">
 +
<Entry Text="{Binding ValueAccessors[NAME].Value}" />
 +
</syntaxhighlight>
 +
''(Replace NAME with the placeholder of your actual trait or property name)''
  
 
=== 2. TraitByName (Traits Only) ===
 
=== 2. TraitByName (Traits Only) ===
Line 20: Line 35:
 
* '''Usage:''' When you explicitly want to query ''only'' traits (e.g., read-only display in the UI).
 
* '''Usage:''' When you explicitly want to query ''only'' traits (e.g., read-only display in the UI).
  
[[Category:Client|Traits]]
+
'''XAML Example (Reading only Trait):'''
[[Category:MAUI|Traits]]
+
<syntaxhighlight lang="xml">
[[Category:Mobile|Traits]]
+
<Entry Text="{Binding TraitByName[TRAIT_NAME].Value}" />
 +
</syntaxhighlight>
 +
''(Replace TRAIT_NAME with the placeholder of your actual trait)''
  
 
=== 3. Values (Raw Data) ===
 
=== 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>.
+
See [[XAML#Values.5BMP_PROPERTY.5D|Values]]
* '''Usage:''' For pure display purposes or evaluations.
+
  
 
----
 
----
 
[[Category:Client|Traits]]
 
[[Category:MAUI|Traits]]
 
[[Category:Mobile|Traits]]
 
  
 
== Commands (Set & Create Values) ==
 
== Commands (Set & Create Values) ==
Line 38: Line 50:
 
=== SetValueCommand ===
 
=== SetValueCommand ===
 
This command on the <code>ContentViewModel</code> orchestrates value assignments and handles the '''creation of new traits''' if necessary.
 
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 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 a editable 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 {{UBIK}} content.
+
* '''Otherwise:''' A trait is added to the {{UBIK}} content.
  
----
+
'''XAML Example (Setting a value):'''
 +
To create traits entirely from scratch (or explicitly overwrite an existing value), pass the <code>Name</code> and <code>Value</code> parameters to the <code>SetValueCommand</code>.
  
== 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">
 
<syntaxhighlight lang="xml">
<controls:SfListViewExt ItemsSource="{Binding Content.Traits}">
+
xmlns:classes="clr-namespace:UBIK.MAUI.Classes;assembly=UBIK.MAUI"
    <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 Command="{Binding SetValueCommand}" Text="Set">
 
     <Button.CommandParameter>
 
     <Button.CommandParameter>
 
         <classes:KeyValueList>
 
         <classes:KeyValueList>
             <classes:KeyValueParameter Key="PropertyName" Value="{Binding Text, Source={x:Reference DateTraitNameInput}}" />
+
             <classes:KeyValueParameter Key="Name" Value="MY_TRAIT_NAME" />
             <classes:KeyValueParameter Key="PropertyValue" Value="{Binding Date, Source={x:Reference DateTestPicker}}" />
+
             <classes:KeyValueParameter Key="Value" Value="MY_TRAIT_VALUE" />
 
         </classes:KeyValueList>
 
         </classes:KeyValueList>
 
     </Button.CommandParameter>
 
     </Button.CommandParameter>
 
</Button>
 
</Button>
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
''(Note: Replace MY_TRAIT_NAME & MY_TRAIT_VALUE with the placeholder of your actual trait or property name/value)''
  
 
----
 
----
  
 
[[Category:Client|Traits]]
 
[[Category:Client|Traits]]
[[Category:MAUI|Traits]]
 
 
[[Category:Mobile|Traits]]
 
[[Category:Mobile|Traits]]
 +
[[Category:WinX|Traits]]
 +
[[Category:Version 5.1|Traits]]

Latest revision as of 08:55, 28 April 2026

Traits

UBIK® Traits provide the ability to define a dynamic list of 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. Please note that traits do not use lazy loading, making them act rather "heavy weight" from a user's perspective.

Supported types:

  • int
  • double
  • string
  • bool
  • date time
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 (Read/Write)

The ValueAccessors acts as a combined dynamic value resolver. It provides a 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 (see PropertyByName).
  3. Default: If neither exists, it returns null.
IC Attention.png'Caution:' Be careful when using ValueAccessors. If you mistype a property name in XAML, you might not notice the error immediately and spend unnecessary time debugging. If you know you strictly need properties, use standard property bindings.

XAML Example (Reading a value):

<Entry Text="{Binding ValueAccessors[NAME].Value}" />

(Replace NAME with the placeholder of your actual trait or property name)

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

XAML Example (Reading only Trait):

<Entry Text="{Binding TraitByName[TRAIT_NAME].Value}" />

(Replace TRAIT_NAME with the placeholder of your actual trait)

3. Values (Raw Data)

See Values


Commands (Set & Create Values)

SetValueCommand

This command on the ContentViewModel orchestrates value assignments and handles the creation of new traits if necessary.

  • If a trait exists: The value will be overwritten.
  • If a editable property exists: The property's value will be overwritten (if it is not locked/read-only).
  • Otherwise: A trait is added to the UBIK® content.

XAML Example (Setting a value): To create traits entirely from scratch (or explicitly overwrite an existing value), pass the Name and Value parameters to the SetValueCommand.

xmlns:classes="clr-namespace:UBIK.MAUI.Classes;assembly=UBIK.MAUI"

<Button Command="{Binding SetValueCommand}" Text="Set">
    <Button.CommandParameter>
        <classes:KeyValueList>
            <classes:KeyValueParameter Key="Name" Value="MY_TRAIT_NAME" />
            <classes:KeyValueParameter Key="Value" Value="MY_TRAIT_VALUE" />
        </classes:KeyValueList>
    </Button.CommandParameter>
</Button>

(Note: Replace MY_TRAIT_NAME & MY_TRAIT_VALUE with the placeholder of your actual trait or property name/value)