CompiledBindings.MAUI 1.0.12-beta1

This is a prerelease version of CompiledBindings.MAUI.
There is a newer version of this package available.
See the version list below for details.
dotnet add package CompiledBindings.MAUI --version 1.0.12-beta1
NuGet\Install-Package CompiledBindings.MAUI -Version 1.0.12-beta1
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="CompiledBindings.MAUI" Version="1.0.12-beta1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add CompiledBindings.MAUI --version 1.0.12-beta1
#r "nuget: CompiledBindings.MAUI, 1.0.12-beta1"
#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 CompiledBindings.MAUI as a Cake Addin
#addin nuget:?package=CompiledBindings.MAUI&version=1.0.12-beta1&prerelease

// Install CompiledBindings.MAUI as a Cake Tool
#tool nuget:?package=CompiledBindings.MAUI&version=1.0.12-beta1&prerelease

CompiledBindings

This library provides {x:Bind} Markup Extension for WPF, MAUI and Xamarin Forms. You can read about {x:Bind} Markup Extension for UWP here. The whole functionality of {x:Bind} for UWP and also many other features are supported.

At XAML compile time, {x:Bind} is converted into C# code. Thus you can't use it in Visual Basis projects.

x:Bind Markup Extension

{x:Bind} Markup Extension have an expression as its first parameter, or the expression is specified by the Path parameter, following by other parameters like Mode, BindBack, Converter, ConverterParameter.

x:Bind usage

Note, that in some examples bellow the TextBlock (WPF) control is used, in others Label (Xamarin Forms).

Property paths

<TextBlock Text="{x:Bind Title}"/>
<TextBlock Text="{x:Bind Movie.Year}"/>

Function calls

<TextBlock Text="{x:Bind Movie.Description.Trim()}"/>
<TextBlock Text="{x:Bind local:MainPage.GenerateSongTitle(Title, Description)}"/>

The first example above is the call of instance method Trim(). The second is the call of static method GenerateSongTitle of MainPage class, wich takes two parameters (multi-binding).

The expression of the {x:Bind} can also have the following operators:

  • binary operators (in round brackets alternatives, which are better for XML): +, -, *, /, = (eq), != (ne), < (lt), > (gt), ⇐ (le), >= (ge)
<Label IsVisible="{x:Bind Movie.Year gt 2000}"/>
  • unary operators: -, +, ! (not)
<Label IsVisible="{x:Bind not IsChanged}"/>
  • logical operators: && (and), || (or)
<Label IsVisible="{x:Bind NoTitle and IsChanged}"/>
  • coalesce operator
<TextBlock Visibility="{x:Bind IsChange ? Collapsed : Visible}"/>

Note, that the Collapsed and Visible values here are inferred from Visibility property.

  • null check operator
<Label IsVisible="{x:Bind Movie.Title ?? 'no title'}"/>
  • cast operator. The class, to which cast is made, must be fully specified with namespace (the namespace must be declared)
<CollectionView x:Name="itemsList"/>
<Label x:DataType="{x:Null}" Text="{x:Bind ((local:Movie)itemsList.SelectedItem).Title}"/>
  • as operator. The class, to which cast is made, must be fully specified with namespace (the namespace must be declared).
<CollectionView x:Name="itemsList"/>
<Label x:DataType="{x:Null}" Text="{x:Bind (itemsList.SelectedItem as local:Movie).Title}"/>

In the example, if the SelectedItem is not a Movie, empty text is set.

  • new operator. The class must be fully specified with namespace
<Label Text="{x:Bind SomeFunction(Property1, new local:Class1(Property2)}" />
  • interpolated string. The interpolated string must start with $ symbol following a string literal in quotes. The string may contain interpolated expressions in {} brackets, with optional format part. The string is resolved when the binding applies, or one of the values of any expression is changed.
<Label Text="{x:Bind $'Decimal value: {DecimalProp:0.###}, Boolean value: {BooleanProp}, String value: {StringProp.TrimStart('0')}'}" />

You can use following constants in the expression:

  • numbers with or wihout decimal seperator (point). For example 2.3
  • true, false
  • null
  • this
  • strings. For example 'some string'
  • characters. The same as strings, for example 'a'. Which type is actually used is mostly inferred during compilation. In case of ambiquity, the cast operator must be used.

Data source

If not specified, the data source of {x:Bind} is the root control/page/window itself. In Xamarin Forms you can specify the data source type with x:DataType attribute.

Because x:DataType attribute is not available for WPF, you can do the following.

  xmlns:mx="http://compiledbindings.com/x"
  • Set the prefix of the namespace as ignorable (in the example together with d namespace)
  mc:Ignorable="d mx"
  • Now you can set the data source type like this
xmlns:local="clr-namespace:CompiledBindingsDemo"
mx:DataType="local:MainViewModel"

Note, that if the data source is specified, the {x:Bind} extensions are only applied if the DataContext (or BindingContext in XF) of the root or corresponding controls is set to an object of the specified type.

If the {x:Bind} Markup Extension is used in a DataTemplate and you don't set the IsItemsSource property to true to the binding, setting the ItemsSource of a collection control (see below), you must specify the data type. For Xamarin Forms with x:DataType attribute. For WPF either with DataType attribute, or alternative with mx:DataType attribute.

You can change the data type anywhere in XAML by setting x:DataType (mx:DataType). You can also use {x:Null} as DataType, except in DataTemplates, to reset the data type. Note, that {x:Null} works differently for standard {Binding} and {x:Bind} extensions. For the first one, it turns off producing compiled binding at compile time, so the expression is only resolved at runtime. For the second one, it sets the data type of the control/page/window itself.

DataType property

You can set the DataType only for a one x:Bind, by setting the corresponding DataType property.

<CollectionView x:Name="itemsList"/>
<Label Text="{x:Bind ((local:Movie)itemsList.SelectedItem).Title, DataType={x:Null}}"/>

IsItemsSource property

If you use {x:Bind} to set the ItemsSource property of a collection control (ListBox, ListView, CollectionView etc), you can set the IsItemsSource property to true, so that the data type of a elements is automatically detected. Than you don't have to specify it for the ItemTemplate.

<CollectionView ItemsSource="{x:Bind Movies, IsItemsSource=true}">
   <CollectionView.ItemTemplate>
       <DataTemplate>
	        <Label Text="{x:Bind Title}"/>
	    </DataTemplate>
   </CollectionView.ItemTemplate>
</CollectionView>

Note, that it works only if the DataTemplate is specifed as a XAML child to the collection control.

x:Bind other parameters

  • Mode Specifies the binding mode, as one of these strings: "OneTime", "OneWay", "TwoWay" or "OneWayToSource". The default is "OneWay"
  • Converter Specifies the converter.
  • ConverterParameter Specifies the converter parameter.
  • BindBack Specifies a expression to use for the reverse direction of a two-way binding. If the property is set, the Mode is automatically set two TwoWay.
  • FallbackValue Specifies a value to display when the source or path cannot be resolved.
  • TargetNullValue Specifies a value to display when the source value resolves but is explicitly null.

The Converter, ConverterParameter, FallbackValue and TargetNullValue can be either an expression, or a {x:Static} markup extension.

Observing changes

If the Mode is not OneTime or OneWayToSource, than a code is generated to observe changes of properties in the {x:Bind} expression. The changes are observed to Dependency Properties, if there are any in the expression, as well as to objects of classes, implementing INotifyPropertyChanged interface.

Binding to asynchronous (returning Task<T>) properties and functions.

If a property's or a function's returning type is Task<T>, its value is taking with await.

For example, you have a function LoadImageAsync in your ViewModel, which asynchronously downloads an image. You can set the image like this:

<Image Source="{x:Bind LoadImageAsync()}" />

While waiting for the value to arrive, the {x:Bind} reports the FallbackValue, if one is available, or the default value of the binding target property. For example:

<Page.Resources>
    <BitmapImage x:Key="defaultImage" UriSource="/Images/download.png" />
</Page.Resources>

<Image Source="{x:Bind LoadImageAsync(), FallbackValue={StaticResource defaultImage}}" />

If an asynchronous function throws an exception, the exception is ignored. The value of the target property is not changed.

Binding to tuples.

Sometimes it is needed to calculate values for many UI properties using the same logic. For example, foreground and background of a TextBlock must be set according to some state or other logic. You can define one property (function), which returns both foreground and background.

public (Brush foreground, Brush background) Colors
{
	get
	{
		switch (this.State)
		{
			case EntityState.Saved:
				return (Brushes.Beige, Brushes.Green);
			case EntityState.NotEdited:
				return (Brushes.White, Brushes.Black);
					
		       ...
		}
	}
}

Than you can use it:

<TextBlock Foreground="{x:Bind Colors.foreground}" Background="{x:Bind Colors.background}"/>

Note, that the Color property is not called twice. Its value is taken only once, saved as local variable in the generated C# code, and than the values are set to the Control's properties.

Binding to events as target.

You can binding to a controls event and have a function at the end of expression, which will be called when the event is triggered. If you want to receive the event parameters, the signature of the function must be the same as the event handler. The function in the expression must be used without parameters.

<TextBox Drop="{x:Bind _viewModel.OnDrop}"/>
public void OnDrop(object sender, System.Windows.DragEventArgs e)
{
}

You can use also a function with any signature, passing the parameters in XAML.

<Button Click="{x:Bind _viewModel.Save(true)}"/>
public void Save(bool parameter)
{
}

x:Set Markup Extension

This library also provides {x:Set} Markup Extension. It has an expression parameter, similar like {x:Bind}, and no other parameters. The data source of {x:Set} is always the root page/control/window itself. The expression is evaluated and set only once at the end of constructors of the page/control/window. If an expression is a static property of some type, than it is similar to {x:Static} Markup Extension.

Binding to methods and extension methods

Instead of a property, you can use a method or an extension method as target of {x:Bind} or {x:Set} Markup Extension with OneTime and OneWay modes. If an instance method is used as a target, it must have only one parameter. An extension method must have two parameters where the first one is the "this" parameter of the control, and the second is the parameter, to which the {x:Bind} or {x:Set} expression is set. To use it you do the following

  xmlns:m="http://compiledbindings.com/"
  • Set the prefix of the namespace as ignorable
  mc:Ignorable="d m mx"
  • For extension methods, the corresponding namespace of the extension class must be specified
  xmlns:extension="using:CompiledBindingsDemo.Extensions"
  • Now use can use methods as target like this
  <Entry m:SetFocused="{x:Bind IsNameFocused} "/>

The extension method for example above can look like this:

public static void SetFocused(this VisualElement visualElement, bool focused)
{
   if (focused)
   {
       visualElement.Focus();
   }
}

Using m: Namespace to bind to any property

Just like binding to methods, you can use m: Namespace to bind to properties. This is usefull, if the {x:Bind} or {x:Set} expression is correct, but you still receive errors. This can happen, because some other part of the build process determins the markup extension as invalid.

For example, in WPF if using single quotes in the expression, you receive the following error:

xmlns:system="using:System"
<TextBlock Text="{x:Bind system:String.Format('{0:0.###} {1}', Quantity, Unit)}" />
Names and Values in a MarkupExtension cannot contain quotes. The MarkupExtension arguments ' system:String.Format('{0:0.###} {1}', Quantity, Unit)}' are not valid.

You can overcome this problem by using m: Namespace to set the Text property:

<TextBlock m:Text="{x:Bind system:String.Format('{0:0.###} {1}', Quantity, Unit)}"

Declaring CLR-Namespaces namespaces with "using" and "global using"

For CLR-Namespaces you can use the "using" syntax. For example

 xmlns:local="using:CompiledBindingsDemo"

You can also declare the CLR-Namespaces globally with "global using" syntax. For {x:Bind} markup extensions in other XAML files you do not have to declare the namespace. Note, this works only for {x:Bind}. If a namespace is used for other purposes, it must be decleared locally.

 xmlns:local="global using:CompiledBindingsDemo"

Settings breakpoints for x:Bind and x:Set extensions

You can set breakpoints in XAML on the lines with x:Bind or x:Set extensions. A breakpoint will be hit whenever the property is set.

BreakpointInXaml

Note, that only one breakpoint per line is possible.

To inspect values of the binding expression you can use the "dataRoot" variable in the Watch window to refer to the binding root object.

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.

This package has no dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.18 162 4/22/2024
1.0.17.6 1,079 9/21/2023
1.0.17.5 201 9/12/2023
1.0.17.4 170 9/6/2023
1.0.17.3 158 9/4/2023
1.0.17.1-beta1 140 6/23/2023
1.0.16 643 5/17/2023
1.0.16-beta1 96 5/11/2023
1.0.15 396 3/11/2023
1.0.14 416 12/2/2022
1.0.13 540 9/20/2022
1.0.12 591 9/16/2022
1.0.12-beta1 136 9/3/2022
1.0.11 526 6/16/2022
1.0.10 448 4/5/2022
1.0.9 408 3/15/2022
1.0.8 262 1/4/2022