CalcBinding Documentation

repository·master·Indexed 20 days ago

https://github.com/alex141/calcbinding

An advanced XAML markup extension that enables complex algebraic, logical, and ternary calculated binding expressions directly in XAML. It eliminates the need for custom IValueConverter implementations and supports static properties, Enum values, System.Math members, and automatic Bool to Visibility conversion. Features include automatic inversion of binding expressions for two-way bindings and support for RelativeSource TemplatedParent to simulate TemplateBinding.

Tokens
2.5K
Snippets
11
Records
12
Agent score
22%

What's inside CalcBinding

  1. Automatic inversion of binding expressions

    master

    CalcBinding can automatically create two-way bindings by mathematically inverting a one-way expression. If you define a binding where a UI property depends on a ViewModel property via a formula, CalcBinding calculates the inverse formula to update the ViewModel when the UI property changes.

    Example: If TextBox.Text depends on ViewModel.A via Math.Sin(A*2)-5, you can write:

    <TextBox Text = "{c:Binding 'Math.Sin(A*2)-5'}">

    CalcBinding will automatically use the inverse expression A = Math.Asin(TextBox.Text + 5) / 2 for the ConvertBack operation.

    Restrictions for automatic inversion:

    1. The binding must include exactly one property path (static or non-static) and only one entry of it.
    2. The expression can only use the following operators and methods: "+", "- (binary)", "*", "/", "Math.Sin", "Math.Cos", "Math.Tan", "Math.Asin", "Math.Acos", "Math.Atan", "Math.Pow", "Math.Log", "!", "- (unary)".
  2. Automatic Bool to Visibility conversion

    master

    When binding a boolean expression to a dependency property of type Visibility, CalcBinding automatically converts the result.

    • true is converted to Visibility.Visible.
    • false is converted based on the FalseToVisibility property.

    FalseToVisibility options:

    1. FalseToVisibility.Collapsed (default)
    2. FalseToVisibility.Hidden

    Automatic inversion also applies: if the target property is Visibility.Visible, it is treated as true; otherwise, it is false.

    Examples:

    <!-- Uses default Collapsed -->
    <Button Content="TargetButton" Visibility="{c:Binding HasPrivileges, FalseToVisibility=Collapsed}"/>
    
    <!-- Using the '!' operator -->
    <Button Content="TargetButton" Visibility="{c:Binding !HasPrivileges}"/>
    
    <!-- Using Hidden instead of Collapsed -->
    <Button Content="TargetButton" Visibility="{c:Binding !HasPrivileges, FalseToVisibility=Hidden}"/>
    <Button Content="TargetButton" Visibility="{c:Binding HasPrivileges, FalseToVisibility=Collapsed}"/>
  3. Use CalcBinding for calculated expressions

    master

    Instead of using MultiBinding with a custom IValueConverter, you can use the c:Binding markup extension to write algebraic or logical expressions directly in XAML. This makes binding expressions shorter and more readable.

    <!-- Before: Standard MultiBinding with Converter -->
    <Label>
      <Label.Content>
        <MultiBinding Converter={x:StaticResource MyCustomConverter}> 
          <Binding A/> 
          <Binding B/> 
          <Binding C/> 
        </MultiBinding>
      </Label.Content>
    </Label>
    
    <!-- After: CalcBinding -->
    <Label Content="{c:Binding A+B+C}" />
  4. Enable CalcBinding tracing

    master

    Tracing is disabled by default. To enable it, add a CalcBindingTraceLevel switch to your app.config file.

    Available levels: All, Off, Critical, Error, Warning, Information, Verbose.

    Example configuration (to see Information level logs):

    <system.diagnostics>
      <switches>
        <add name="CalcBindingTraceLevel" value="Information"/>
      </switches>
    </system.diagnostics>
  5. Simulate TemplateBinding using RelativeSource

    master

    CalcBinding does not have a dedicated TemplateBinding markup extension. To achieve similar behavior within a ControlTemplate, set the RelativeSource property to TemplatedParent.

    Example:

    <Button Content="Button" Width="100">
        <Button.Template>
            <ControlTemplate>
                <TextBox Width="{c:Binding Width+10, RelativeSource={RelativeSource TemplatedParent}}"/>
            </ControlTemplate>
        </Button.Template>
    </Button>
    <TextBox Width="{c:Binding Width+10, RelativeSource={RelativeSource TemplatedParent}}"/>
  6. Configure String and Char constants with SingleQuotes

    master

    Because XAML uses double quotes for attributes, writing string constants in a binding path can be difficult. By default, CalcBinding treats all quotes (single or double) as double quotes (Strings).

    To support Char constants, use the SingleQuotes property.

    • SingleQuotes=False (Default): All quotes (\' or &quot;) are treated as String constants.
    • SingleQuotes=True: All quotes are treated as Char symbols.

    Restrictions: You cannot use both Char and String constants in the same expression.

    Examples:

    <!-- String mode (Default) -->
    <TextBox Text="{c:Binding (Name + \' \' + Surname)}" />
    
    <!-- Char mode -->
    <TextBox Text="{c:Binding 'Symbol == &quot;S&quot;?4:5', SingleQuotes=True}"/>
    <TextBox Text="{c:Binding 'Symbol == &quot;S&quot;?4:5', SingleQuotes=True}"/>
  7. Use Enums in CalcBinding expressions

    master

    Starting with version 2.3, you can use Enum values or properties in your expressions using the syntax: xmlNamespace:EnumClass.Value.

    Examples

    <!-- Comparing a property to an Enum value -->
    <CheckBox Content="Started" IsChecked="{c:Binding 'State==local:StateEnum.Start'}" />
    
    <!-- Using Enums in a ternary expression -->
    <Button Background="{c:Binding 'EnumValue == local:MyEnum.Value1 ? media:Brushes.Green : media:Brushes.Red'}"/>

    Restriction: Ternary Operator Spacing

    Ensure there is a delimiter (like a space) between the ternary : operator and the Enum path.

    Correct:

    <TextBox Text="{c:Binding '(A == 2)?sys:Visibility.Visible : sys:Visibility.Hidden'}"/>

    Incorrect:

    <TextBox Text="{c:Binding '(A == 2)?sys:Visibility.Visible:sys:Visibility.Hidden'}"/>
    <CheckBox Content="Started" IsChecked="{c:Binding 'State==local:StateEnum.Start'}" />
  8. Use static properties in CalcBinding

    master

    Starting with version 2.3, you can include static properties in your binding paths using the syntax: xmlNamespace:Class.StaticProperty.NestedProperty.

    Ensure the xmlNamespace is correctly mapped in your XAML header.

    Examples

    <!-- Accessing a local static property -->
    <TextBox Text="{c:Binding 'local:Class.NestedProp.Prop1 + local:OtherStaticClass.PropB + PropC'}"/>
    
    <!-- Using static properties in a ternary expression -->
    <Button Background="{c:Binding '(A > B ? media:Brushes.LightBlue : media:Brushes.White)'}"/>

    Restriction: Ternary Operator Spacing

    Just like standard properties, you must use a delimiter (like a space) between the ternary : operator and the static property path.

    Correct:

    <TextBox Text="{c:Binding '(A == 2)?local:Class.Prop1 : local:Class.Prop2}"/>

    Incorrect:

    <TextBox Text="{c:Binding '(A == 2)?local:Class.Prop1: local:Class.Prop2}"/>
    <TextBox Text="{c:Binding 'local:Class.NestedProp.Prop1 + local:OtherStaticClass.PropB + PropC'}"/>
  9. Write algebraic and logical expressions with c:Binding

    master

    You can use source property paths, strings, digits, and various operators within a c:Binding expression.

    Supported Operators

    • Algebraic: (, ), +, -, *, /, %, ^
    • Logical: !, &&, ||, &, |
    • Comparison: <, >, <=, >=, ==, !=
    • Ternary: condition ? expression_1 : expression_2

    XML-Safe Aliases

    Since XAML is XML-based, certain characters like < and & must be escaped or replaced with aliases:

    OperatorAliasComment
    &&andLogical AND
    ||orLogical OR
    <lessLess than
    <=less=Less than or equal

    Examples

    Algebraic:

    <TextBox Text="{c:Binding A+B+C}"/>
    <TextBox Text="{c:Binding A*(B+C)}"/>
    <TextBox Text="{c:Binding '(A == 1) ? 10 : 20'}"/>

    Logical:

    <CheckBox Content="!IsChecked" IsChecked="{c:Binding !IsChecked}"/>
    <TextBox Text="{c:Binding 'IsChecked and IsFull'}"/>
    <TextBox Text="{c:Binding '(A == 1) and (B less= 5)'}"/>

    Restriction: Ternary Operator Spacing

    To avoid path analysis errors, you must separate the identifier (property or namespace) from the ternary : operator using a delimiter like a space or another operator.

    Correct:

    <TextBox Text="{c:Binding '(A == 2)?IsChecked : IsFull}"/>
    <TextBox Text="{c:Binding '(A == 2) ? IsChecked : 4 + IsFull}"/>

    Incorrect:

    <TextBox Text="{c:Binding '(A == 2)?IsChecked:IsFull}"/>
    <TextBox Text="{c:Binding A+B+C}"/>
  10. Use System.Math members in paths

    master

    You can use any member of the System.Math class directly in your binding expression as if you were writing C# code.

    Examples

    <TextBox Text="{c:Binding Math.Sin(A*Math.PI/180), StringFormat={}{0:n5}}"/>
    <TextBox Text="{c:Binding A*Math.PI}"/>

    Restriction: Do not use static property syntax for Math

    Math is a standalone feature. Do not use the xmlNamespace:Math syntax. Use Math directly.

    Correct:

    <TextBox Text="{c:Binding Math.Sin(10)+20}"/>

    Incorrect:

    <TextBox Text="{c:Binding sys:Math.Sin(10)+20}"/>
    <TextBox Text="{c:Binding Math.Sin(A*Math.PI/180), StringFormat={}{0:n5}}"/>
  11. General restrictions and limitations

    master

    When using CalcBinding, be aware of the following constraints:

    1. Nullable Types: Nullable value types are not supported in reverse bindings (e.g., Mode=OneWayToSource).
    2. Custom Converters: CalcBinding does not support user-defined IValueConverter implementations.
    3. Method Support: You cannot use arbitrary .NET class methods in a path expression; only methods from the Math class are supported.
    4. Binding Mode Changes (v2.2.5.2+): In newer versions, BindingMode.Default is used instead of TwoWay. If you need a TwoWay binding on a property that defaults to OneWay (like Label.Visibility), you must explicitly set Mode=TwoWay in your XAML.

    Example of explicit TwoWay mode:

    <Button Content="TargetButton" Visibility="{c:Binding !HasPrivileges, Mode=TwoWay}"/>