Difference between revisions of "Traits"
| Line 1: | Line 1: | ||
| − | = | + | = Traits = |
| − | '''{{UBIK}} Traits''' provide the ability to define a dynamic list of | + | '''{{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. |
{{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 10: | ||
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 ( | + | === 1. ValueAccessors (Read/Write) === |
| − | The <code>ValueAccessors</code> acts as a combined dynamic value resolver. It | + | 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 [[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]}" /> | ||
| + | </syntaxhighlight> | ||
| + | ''(Replace NAME with the placeholder of your actual trait or property name)'' | ||
=== 2. TraitByName (Traits Only) === | === 2. TraitByName (Traits Only) === | ||
| Line 20: | Line 28: | ||
* '''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). | ||
| − | + | '''XAML Example (Reading only Trait):''' | |
| − | + | <syntaxhighlight lang="xml"> | |
| − | + | <Entry Text="{Binding TraitByName[TRAIT_NAME]}" /> | |
| + | </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>. | 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. | * '''Usage:''' For pure display purposes or evaluations. | ||
| + | |||
| + | '''XAML Example (Reading raw data):''' | ||
| + | <syntaxhighlight lang="xml"> | ||
| + | <Entry Text="{Binding Values[NAME]}" /> | ||
| + | </syntaxhighlight> | ||
| + | ''(Replace NAME with the placeholder of your actual trait or property name)'' | ||
---- | ---- | ||
| − | |||
| − | |||
| − | |||
| − | |||
== Commands (Set & Create Values) == | == Commands (Set & Create Values) == | ||
| Line 40: | Line 52: | ||
* '''If the trait exists:''' The value will be overwritten. | * '''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 a property exists:''' The property's value will be overwritten (if it is not locked/read-only). | ||
| − | * '''If neither exists:''' A | + | * '''If neither exists:''' 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>. | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
<Button Command="{Binding SetValueCommand}" Text="Set"> | <Button Command="{Binding SetValueCommand}" Text="Set"> | ||
<Button.CommandParameter> | <Button.CommandParameter> | ||
<classes:KeyValueList> | <classes:KeyValueList> | ||
| − | <classes:KeyValueParameter Key=" | + | <classes:KeyValueParameter Key="Name" Value="MY_TRAIT_NAME" /> |
| − | <classes:KeyValueParameter Key=" | + | <classes:KeyValueParameter Key="Value" Value="My Trait Value" /> |
</classes:KeyValueList> | </classes:KeyValueList> | ||
</Button.CommandParameter> | </Button.CommandParameter> | ||
</Button> | </Button> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| + | ''(Note: Customizers can replace the static string placeholders with dynamic bindings to controls like Entry or DatePicker as needed)'' | ||
---- | ---- | ||
Revision as of 06:48, 28 April 2026
Contents
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.
| 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 (Read/Write)
The ValueAccessors 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.
- Property Fallback: If no trait is found, it queries a regular UBIK® Property with that name (see PropertyByName).
- Default: If neither exists, it returns
null.
XAML Example (Reading a 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):
(Replace TRAIT_NAME with the placeholder of your actual trait)
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.
XAML Example (Reading raw data):
(Replace NAME with the placeholder of your actual trait or property name)
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 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.
<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: Customizers can replace the static string placeholders with dynamic bindings to controls like Entry or DatePicker as needed)
