CalcBindingAva 2.5.3

dotnet add package CalcBindingAva --version 2.5.3                
NuGet\Install-Package CalcBindingAva -Version 2.5.3                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CalcBindingAva" Version="2.5.3" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add CalcBindingAva --version 2.5.3                
#r "nuget: CalcBindingAva, 2.5.3"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install CalcBindingAva as a Cake Addin
#addin nuget:?package=CalcBindingAva&version=2.5.3

// Install CalcBindingAva as a Cake Tool
#tool nuget:?package=CalcBindingAva&version=2.5.3                

CalcBindingAva

CalcBindingAva is a fork of CalcBinding (Based on commit fc01ad5).

CalcBindingAva supports Avalonia 11.0.4 and .Net 6.0 only.

CalcBinding is an advanced Binding markup extension that allows you to write calculated binding expressions in xaml, without custom converters.

CalcBindingAva can automaticaly perfom different algebraic operations, inverse your expression and more. CalcBindingAva makes binding expressions shorter and more user-friendly.

Install

CalcBindingAva is available at NuGet. You can install package using:

PM> Install-Package CalcBindingAva 

Or download source code and compile CalcBindingAva.csproj by vs2022.

Overview

Following example shows xaml snippets with standart Binding and with CalcBindingAva in very simple case:

Before:

<Label>
  <Label.Content>
  <MultiBinding Conveter={x:StaticResource MyCustomConverter}> 
    <Binding A/> 
    <Binding B/> 
    <Binding C/> 
  </MultiBinding>
  </Label.Content>
</Label> 

(without MyCustomConveter declaration and referencing to it in xaml)

After:

Add xmlns to your axaml code:

xmlns:c="clr-namespace:CalcBinding;assembly=CalcBindingAva"

MVVM Window example:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="using:Avalonia.Demo1.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
		xmlns:c="clr-namespace:CalcBinding;assembly=CalcBindingAva"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="Avalonia.Demo1.Views.MainWindow"
        x:DataType="vm:MainWindowViewModel"
        Icon="/Assets/avalonia-logo.ico"
        Title="Avalonia.Demo1">
<Label Content="{c:Binding A+B+C }" />

Key features and restrictions:

  1. One or many source properties in Path with many available operators: description
<Label Content="{c:Binding A*0.5+(B.NestedProp1/C - B.NestedProp2 % C) }" />
<c:Binding 'A and B or C' />
  1. One or many static properties in Path: description
<TextBox Text="{c:Binding 'local:StaticClass.Prop1 + local:OtherStaticClass.NestedProp.PropB + PropC'}"/>
<Button Background="{c:Binding '(A > B ? media:Brushes.LightBlue : media:Brushes.White)'}"/>
  1. Properties and methods of class System.Math in Path: description
<TextBox Text="{c:Binding 'Math.Sin(Math.Cos(A))'}"/>
  1. Enum types like constants or source properties in Path: description
<TextBox Text="{c:Binding '(EnumValue == local:CustomEnum.Value1 ? 10 : 20)'}"/>
  1. Automatic inversion of binding expression if it's possible: description
<TextBox Text = "{c:Binding 'Math.Sin(A*2)-5'}"/> {two way binding will be created}
  1. NO conversion of bool expression to Visibility and back, because Avalonia use bool only.

  2. Other features such as string and char constants support and other: description

  3. Tracing

  4. General restrictions: description

  5. Casts for a part of DynamicExpresso built-in types , and add some relative keywords

Documentation

1. Source properties and operators

You can write any algebraic, logical and string expressions, that contain source property pathes, strings, digits, all members of class Math and following operators:

"(", ")", "+", "-", "*", "/", "%", "^", "!", "&&","||",
"&", "|", "?", ":", "<", ">", "<=", ">=", "==", "!="};

and ternary operator in form of 'bool_expression ? expression_1 : expression_2'

One should know, that xaml is generally xml format, and xml doesn't support using of following symbols when setting attribute value: &, <. Therefore, CalcBinding supports following aliases for operators that contain these symbols:

operator alias comment
&& and
|| or not nessesary, just for symmetry
< less
less=

Examples

Algebraic
<TextBox Text="{c:Binding A+B+C}"/>
<TextBox Text="{c:Binding A-B-C}"/>
<TextBox Text="{c:Binding A*(B+C)}"/>
<TextBox Text="{c:Binding 2*A-B*0.5}"/>
<TextBox Text="{c:Binding A/B, StringFormat={}{0:n2} --StringFormat is used}"/> {with string format}
<TextBox Text="{c:Binding A%B}"/>
<TextBox Text="{c:Binding '(A == 1) ? 10 : 20'}"/> {ternary operator}
Logic
<CheckBox Content="!IsChecked" IsChecked="{c:Binding !IsChecked}"/>
<TextBox Text="{c:Binding 'IsChecked and IsFull'}"/> {'and' is equvalent of '&&'}
<TextBox Text="{c:Binding '!IsChecked or (A > B)'}"/> {'or' is equvalent of '||', but you can leave '||'}
<TextBox Text="{c:Binding '(A == 1) and (B less= 5)'}"/> {'less=' is equvalent of '<='}
<TextBox Text="{c:Binding (IsChecked || !IsFull)}"/>

Restrictions:

  1. Identifiers that make up the source property path, should be separated from operator ':' by any operator or delimititer (single quote, space etc.) in ternary operator:
<TextBox Text="{c:Binding '(A == 2)?IsChecked : IsFull'}"/> 
<TextBox Text="{c:Binding '(A == 2)?IsChecked :!IsFull'}"/> 
<TextBox Text="{c:Binding '(A == 2) ? IsChecked :4 + IsFull'}"/> 
wrong:
<TextBox Text="{c:Binding '(A == 2)?IsChecked:IsFull'}"/> 

That restricition is caused by path analyzer work that finds static properties

  1. Expressions between operator ':' should return same types or types that can be implicitly converted, even though one of the expressions will not be selected
right:
<TextBox Text="{c:Binding '(A == 2) ? 111L : ((sbyte)123)'}"/> 
<TextBox Text="{c:Binding '\' ObjItem: \' + ((ObjItem is string) ? (ObjItem as string) : (233).ToString())'}"/> 
wrong:
<TextBox Text="{c:Binding '(A == 2) ? 111UL : 123'}"/> 
<TextBox Text="{c:Binding '\' ObjItem: \' + ((ObjItem is string) ? ObjItem : \'233\')'}"/> 

2. Static properties

Beginning with version 2.3 CalcBinding supports static properties in binding expression. You can write pathes that begin with static property of any class and have any number of properties following behind static property. CalcBinding uses following syntax of static property path declaration:

'xmlNamespace:Class.StaticProperty.NestedProperty' etc.

where:

  1. xmlNamespace - usual xml namespace that is mapped to normal namespace in a header of xaml file with other namespaces definitions.

  2. Class - name of class that exists in namespace whereto xmlNamespace is mapped

  3. StaticProperty - static property of class Class

  4. .NestedProperty etc - chain of properties following behind StaticProperty

Examples:

<TextBox Text="{c:Binding 'local:Class.NestedProp.Prop1 + local:OtherStaticClass.PropB + PropC'}"/>
<Button Background="{c:Binding '(A > B ? media:Brushes.LightBlue : media:Brushes.White)'}"/>

where local and media are defined in a header of xaml file:

<<UserControl x:Class="WpfExample.FifthPage"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:local="clr-namespace:WpfExample"
           xmlns:media ="clr-namespace:System.Windows.Media;assembly=PresentationCore">
   ...
</UserControl>

Restrictions

  1. As for non-static property pathes for static property pathes following rule is applied: you should put any delimiter or operator between ':' operator of ternary operator and identifiers (namespace or property) that make up static property path:
right:
<TextBox Text="{c:Binding '(A == 2)?local:Class.Prop1 : local:Class.Prop2}"/> 
<TextBox Text="{c:Binding '(A == 2)?local:OtherClass.IsChecked :!local.OtherClass.IsFull}"/> 
<TextBox Text="{c:Binding '(A == 2) ? local:Class.A :4 + local:Class.B}"/> 
wrong:
<TextBox Text="{c:Binding '(A == 2)?local:Class.Prop1: local:Class.Prop2}"/> 
<TextBox Text="{c:Binding '(A == 2)?local:OtherClass.IsChecked:local.OtherClass.IsFull}"/> 
<TextBox Text="{c:Binding '(A == 2) ? local:Class.A:4+local:Class.B}"/> 

3. Math class members

You can use in path property any members of System.Math class in native form as if you are writing usual C# code:

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

Restrictions

  1. Although CalcBinding supports static properties, Math class is a standalone feature that was created and used before static properties were supported. For this reason you shouldn't use static property syntax with members of Math class.
right:
<TextBox Text="{c:Binding A*Math.PI}" /> 
<TextBox Text="{c:Binding Math.Sin(10)+20}" /> 
wrong:
<xmlns:sys="clr-namespace:System;assembly=mscorlib">
...
<TextBox Text="{c:Binding A*sys:Math.PI}" /> 
<TextBox Text="{c:Binding sys:Math.Sin(10)+20}" /> 

4. Enums

Beginning with version 2.3 CalcBinding supports Enums expressions in binding expression. You can write enum values or properties that have Enum type (static properties too). CalcBinding uses following syntax of declaration enum value:

'xmlNamespace:EnumClass.Value'

where:

  1. xmlNamespace - usual xml namespace that is mapped to normal namespace in a header of xaml file with other namespaces definitions.

  2. EnumClass - name of enum class that exists in namespace whereto xmlNamespace is mapped

Examples:

<CheckBox Content="Started" IsChecked="{c:Binding 'State==local:StateEnum.Start'}" />
<Button Background="{c:Binding 'EnumValue == local:MyEnum.Value1 ? media:Brushes.Green : media:Brushes.Red'}"/>

where

  1. local and media are defined in a header of xaml file: xml <<UserControl x:Class="WpfExample.FifthPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:local="clr-namespace:WpfExample" xmlns:media ="clr-namespace:System.Windows.Media;assembly=PresentationCore"> ... </UserControl>

  2. StateEnum, MyEnum - custom Enums

  3. StateEnum.Start, MyEnum.Value1 - values of custom Enums

  4. Brushes - standart class with static Brush properties

  5. Brushes.Green, Brushes.Red - static properties of class Brushes

Restrictions

  1. As for static property pathes for Enum constants following rule is applied: you should put any delimiter or operator between ':' operator of ternary operator and identifiers (namespace or property) that make up Enum path:
Avalonia doesn't contain Visibility enum.
right:
<TextBox Text="{c:Binding '(A == 2)?sys:Visibility.Visible : sys:Visibility.Hidden}"/> 
<TextBox Text="{c:Binding '(A == 2)?local:MyEnum.Value1 : local.MyEnum.Value2}"/> 
wrong:
<TextBox Text="{c:Binding '(A == 2)?sys:Visibility.Visible:sys:Visibility.Hidden}"/> 
<TextBox Text="{c:Binding '(A == 2)?local:MyEnum.Value1: local.MyEnum.Value2}"/> 
<TextBox Text="{c:Binding '(A == 2)?local:MyEnum.Value1 :local.MyEnum.Value2}"/> 

5. Automatic inversion of binding expression

For examle, you have to create two way binding from viewModel with double property A and Content property of TextBox. TextBox.Content depends on property 'A' by following formula: 'Math.Sin(A*2)-5'

All you have to do is to write:

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

CalcBinding recognizes that this expression has inversed expression 'A = Math.Asin(TextBox.Content + 2) / 2' and will use this expression for conversion dependency property TextBox.Text to property A of ViewModel when Text of textBox changes.

Previous expression equivalents to following usual code:

<TextBox Text = "{Binding Path=A, Conveter={x:StaticResource MyMathConverter}">
public class MyMathConverter : IValueConverter
{
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
          var source = (int)value;
          return Math.Sin(source*2)-5;
        }
        
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {        
          var res = Double.Parse(value);
          return (int)(Math.Asin(res + 5) / 2);
        }
}

Restrictions of creating inversed expression

  1. Binding must include only one property path (static or non-static) and only one entry of it

  2. Binding can contain only following operators and methods:

"+", "- (binary)", "*", "/", "Math.Sin", "Math.Cos", "Math.Tan", "Math.Asin", 
"Math.Acos", "Math.Atan","Math.Pow", "Math.Log", "!", "- (unary)"};

6. NO Bool to Visibility automatic conversion in Avalonia

7. Other feautures

String, Char and SingleQuotes mode

Xaml is markup language based on xml language and xml doesn't support double-quotes signs in attribute values. Xaml doesn't support double-quotes too, futhermore it has problems with supporting single-quote character in Path value: in one expressions is works, in other - no. In order to give an opportunity of writing the most compact and readable string constants in the Path (\', or &apos; or &quot;) CalcBinding doesn't make difference between double and single quotes - all quotes are considered as double quotes by defaults. For example:

<TextBox Text="{c:Binding (Name + \' \' + Surname)}" />
<TextBox Text="{c:Binding (IsMan?\'Mr\':\'Ms\') + \' \' + Surname + \' \' + Name}"/>

However, in this case we loose the ability of supporting Char constants. Therefore beginning with version 2.3 CalcBinding has new property - SingleQuotes. If property is true, CalcBinding considers that all quotes - double and single, are single quotes. So \'A\' and &quot;A&quot; are Char symbols in that mode. If property is false, then single and double quotes are considered as double quotes, it is variant by defaults. So \'A\' and &quot;A&quot; are String constants in that mode. Examples of Char supporting:

<TextBox Text="{c:Binding 'Symbol == &quot;S&quot;?4:5', SingleQuotes=True}"/> {can't use no \' nor &apos; symbols because of xaml compiler generates error when parses == operator}

where Symbol - Char property.

Restrictions:
  1. Simultaneous using of Char and String constants is not supported in this version.

TemplateBinding

Althouth CalcBinding hasn't yet analog for TemplateBinding, as temporary solution you can write as follow:

<Button Content="Button" Width="100">
    <Button.Template>
        <ControlTemplate>
            <TextBox Width="{c:Binding Width+10, RelativeSource={RelativeSource TemplatedParent}}"/>
        </ControlTemplate>
    </Button.Template>
</Button> 

Setting RelativeSource property to TemplatedParent value makes CalcBinding similar to TemplateBinding

8. Tracing

All calcbinding traces are disabled by default due to huge amount of trace messages in some scenarios (see bug 44).

To enable traces, you need to specify minimal tracing level. Add this code to your app.config file to see all Information or higher priority logs:

  <system.diagnostics>
    <switches>
      <add name="CalcBindingTraceLevel" value="Information"/>
    </switches>
  </system.diagnostics>

Other available tracing levels:

  • All,
  • Off,
  • Critical,
  • Error,
  • Warning,
  • Information,
  • Verbose,

For more information, go to msdn: SourceSwitch

9. General restrictions

  1. Nullable value types doesn't supported in reverse binding (e.g. mode OneWayToSource)

  2. CalcBinding doesn't support your custom conveters at all now. If you need this feature, create new issue and put your using scenario in order to I can see that it is necessary

  3. In path expression you can't use any methods of .Net classes except of Math class.

10. Casts for a part of DynamicExpresso built-in types , and add some relative keywords

Casts for the following types

Object object 
Boolean bool 
Char char
String string
SByte sbyte Byte byte
Int16 short UInt16 ushort Int32 int UInt32 uint Int64 long UInt64 ulong
Single float Double double Decimal decimal 
DateTime TimeSpan
Guid

New keywords

true false is as

Examples

<TextBox Text="{c:Binding '(A == 2) ? 111L : ((sbyte)123)'}"/>
<TextBox Text="{c:Binding '\' ObjItem: \' + ((ObjItem is string) ? (ObjItem as string) : \'Unknown\')'}"/>

What is inside?

CalcBinding uses DynamicExpresso library to parse string expression to Linq Expression and compiled expression tree for binding. DynamicExpresso is in fact a fork of DynamicLinq library, with many advantages and bug fixes compared with DynamicLinq (e.x. floating point parsing depending on CurrentCulture damn bug).

String expression is parsed only one time, when binding is initialized. In init section CalcBinding analyzer finds tokens in path expression: property path, static property path, Math expression and Enum expression. When binding is triggered first time, special binding converter replaces each property path and static propert path with variable of appropriate type and call DynamicExpresso to compile expression into delegate that takes new variables.

Working with the compiled expression increases speed of binding compared with parsing of string expression each time. On the development machine, these times are 0.03s for parsing each time and 0.001-0.003 s for working with the compiled expression

Notes

  1. Enum constants are using in expression for Dynamic Expresso directly, with collection of types of known Enums.
  2. Binding for collections (ListView, ListBox, DataGrid etc) are created as many times how many times it were declared in xaml. For example, if you have ListView with 10000 elements, and each element have template consisting of 5 controls which are all binded then only 5 Binding instances would be created.
  3. If one or more property pathes changes type of resulting property then compiling expression is recompilied.

Q&A

1. I wrote logical expression A && B, A < B, A <= B, but my xaml doesn't compile, what's wrong?

As Xaml is generally xml format, some symbols are denied and one should use it's aliases instead os its. See operators aliases table in section Source properties and operators

2. I wrote string expression A + " some text", but my xaml doesn't compile, what's wrong?

In markup extension we can't use double quotes, so we can use single quotes and backslash for escaping \' or xml escape symbol &quot;. See section String, Char and SingleQuotes mode

3. Can I use CalcBinding instead of TemplateBinding?

Yes, you can, but with setting RelativeSource property, see section TemplateBinding

Release notes

version 2.5.3

  • Support casts for a part of DynamicExpresso built-in types , and add some relative keywords

version 2.5.2.0

Donation

If you like this project you are welcome to support it!

Go to CalcBinding

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on CalcBindingAva:

Package Downloads
BestChat.Platform.UI.Desktop

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.5.3 532 9/22/2023
2.5.2 118 9/19/2023

Support Avalonia 11.0.4 and .Net 6.0