Bindings and Data Context

Bindings and Data Context

The Matrix Framework uses bindings to create connections between services and propagate data through the service tree.

Data Context

Context Inheritance

Services inherit data context from their parents:

<ServiceNode Name="OrderSystem">
    <!-- Set data context for all child services -->
    <ServiceNode.DataContext>
        <OrderSystemContext>
            <Property Name="CurrentUser" Value="{Binding User}" />
            <Property Name="Settings" Value="{Binding AppSettings}" />
        </OrderSystemContext>
    </ServiceNode.DataContext>
    
    <ServiceNode Name="OrderProcessor">
        <!-- Inherits OrderSystemContext -->
        <MessageHandler Path="/orders/create">
            <!-- Access inherited context -->
            <ValidateUser User="{Binding CurrentUser}" />
            <ApplySettings Settings="{Binding Settings}" />
        </MessageHandler>
    </ServiceNode>
</ServiceNode>

Context Overriding

Services can override inherited context:

<ServiceNode Name="PaymentProcessor">
    <!-- Override specific context properties -->
    <ServiceNode.DataContext>
        <Property Name="PaymentSettings" 
                 Value="{Binding Settings.Payment}" />
        <Property Name="MerchantId" 
                 Value="{Binding Settings.MerchantId}" />
    </ServiceNode.DataContext>
</ServiceNode>

Binding Types

Property Binding

Bind service properties to data context:

<ServiceNode Name="OrderProcessor">
    <!-- Bind service properties -->
    <ServiceNode.Properties>
        <Property Name="MaxOrderSize" 
                 Value="{Binding Settings.MaxItems}" />
        <Property Name="ValidationRules" 
                 Value="{Binding Rules.Order}" />
    </ServiceNode.Properties>
    
    <!-- Use bound properties -->
    <MessageHandler Path="/orders/create">
        <ValidateOrder MaxItems="{Binding MaxOrderSize}"
                      Rules="{Binding ValidationRules}" />
    </MessageHandler>
</ServiceNode>

Message Binding

Bind message data to handlers:

<ServiceNode Name="OrderManager">
    <MessageHandler Path="/orders/create">
        <!-- Bind message properties -->
        <Parameter Name="OrderData" 
                  Value="{Binding Message.Body}" />
        <Parameter Name="CustomerId" 
                  Value="{Binding Message.Headers.CustomerId}" />
        
        <!-- Two-way binding for response -->
        <Response Path="/orders/created">
            <Property Name="OrderId" 
                     Value="{Binding Result.Id, Mode=TwoWay}" />
            <Property Name="Status" 
                     Value="{Binding Result.Status, Mode=TwoWay}" />
        </Response>
    </MessageHandler>
</ServiceNode>

Command Binding

Bind commands to message handlers:

<ServiceNode Name="OrderAPI">
    <!-- Define commands -->
    <ServiceNode.Commands>
        <Command Name="CreateOrder" 
                 CanExecute="{Binding Permissions.CanCreateOrder}">
            <Parameter Name="OrderData" />
            <Parameter Name="CustomerId" />
        </Command>
    </ServiceNode.Commands>
    
    <!-- Bind commands to messages -->
    <MessageHandler Path="/api/orders/create"
                   Command="{Binding Commands.CreateOrder}">
        <CommandParameter Name="OrderData" 
                         Value="{Binding Message.Body}" />
        <CommandParameter Name="CustomerId" 
                         Value="{Binding Message.User.Id}" />
    </MessageHandler>
</ServiceNode>

Binding Modes

One-Way Binding

Data flows in one direction:

<ServiceNode Name="MetricsCollector">
    <!-- One-way binding from source -->
    <Property Name="OrderCount" 
             Value="{Binding Source.Metrics.Orders, Mode=OneWay}" />
    
    <!-- One-way binding to target -->
    <Property Name="TotalOrders" 
             Value="{Binding Target.Dashboard.Orders, Mode=OneWayToSource}" />
</ServiceNode>

Two-Way Binding

Data flows in both directions:

<ServiceNode Name="InventorySync">
    <!-- Two-way binding for stock levels -->
    <Property Name="StockLevels" 
             Value="{Binding Inventory.Stock, Mode=TwoWay}">
        <Binding.UpdateTrigger>
            <Trigger Path="/inventory/updated" />
            <Trigger Path="/stock/changed" />
        </Binding.UpdateTrigger>
    </Property>
</ServiceNode>

Value Converters

Data Conversion

Transform data during binding:

<ServiceNode Name="OrderNormalizer">
    <ServiceNode.Resources>
        <!-- Define converters -->
        <Converter Name="PriceConverter">
            <Convert From="string" To="decimal" />
        </Converter>
        
        <Converter Name="DateConverter">
            <Convert From="string" To="datetime" />
        </Converter>
    </ServiceNode.Resources>
    
    <!-- Use converters in bindings -->
    <Property Name="OrderTotal" 
             Value="{Binding Order.Total, 
                    Converter=PriceConverter}" />
    <Property Name="OrderDate" 
             Value="{Binding Order.Date, 
                    Converter=DateConverter}" />
</ServiceNode>

Best Practices

  1. Data Context

    • Keep context focused
    • Document inheritance
    • Handle missing data
    • Validate bindings
  2. Binding Design

    • Choose appropriate modes
    • Use converters when needed
    • Handle binding errors
    • Monitor binding health
  3. Performance

    • Minimize binding chains
    • Use appropriate update triggers
    • Cache converted values
    • Profile binding updates