Missed the Hot Design AMA? The recording is available → Watch now

XAML Fundamentals for Web & Mobile: Advanced Binding Techniques

XAML platforms, including WPF, Silverlight, Uno Platform, and WinUI, implement the MVVM (Model-View-ViewModel) pattern to separate UI declaration from application logic. The View Model serves as an intermediary layer that exposes data and commands to the View without requiring direct knowledge of UI implementation details.

Data binding enables this architecture by automatically synchronizing UI elements with View Model properties. When data changes in the View Model, the UI updates without explicit code. This declarative approach reduces boilerplate and improves maintainability.

Traditional binding has limitations that might feel familiar: no compile-time checking, no binding to methods, no constructor parameters in XAML, and the constant hunt for silent binding failures in your output window.

Modern XAML platforms introduce x:Bind, a compiled binding mechanism available in Uno Platform and WinUI. This markup extension generates code at compile time, providing type safety, improved performance, and something developers have wanted for years: the ability to bind directly to methods, pass multiple parameters, and even work with dependency injection containers.

This tutorial examines practical scenarios where x:Bind shines: binding to methods with parameters, handling constructor arguments, integrating with dependency injection, and achieving multi-binding without converters. You’ll build working examples that demonstrate these binding fundamentals and learn when to stick with traditional Binding versus embracing the compiled approach.

When to use x:Bind

In the WPF era, a utility class called ObjectDataProvider added functionality for more advanced data binding scenarios. 

ObjectDataProvider doesn’t exist in WinUI or Uno; however, many of its capabilities can be replicated with the x:Bind markup extension. Because x:Bind declarations are compiled, they are very efficient, and types are checked at build time. This provides a simple and reliable way to support more complex binding relationships. 

While x:Bind supports the same functionality as Binding and much more, you won’t necessarily want to replace every use of Binding with x:Bind. One of the significant differences is that Binding always refers to the DataContext of the View. However, x:Bind, by default, uses the scope of the View itself, so any property or method you reference with x:Bind must refer to an element in the View or exist within the code behind. This often means declaring a strongly typed property for your View Model in your View code. It allows you to specify, via namespaces, any other static method or property that can be pretty useful. 

Passing Parameters to the Constructor

There are many ways to instantiate a View Model, either from code behind or even in the XAML view itself. One of the limitations of the latter approach is that there is no mechanism in XAML to specify parameters for the constructor. 

Knowing that x:Bind allows us to specify functions, we are no longer limited to establishing “XAML safe” classes. For example, you cannot refer to a constructor directly as an x:Bind function, but you can call a static method that itself calls the constructor and returns an instance of the object. 

				
					public static PlanetViewModel Create(string planetName) 
        { 
            return new PlanetViewModel(planetName); 
        } 
				
			

Using Dependency Injection

While this provides a method to complex code any data source from your XAML, you will probably want a more structured approach to retrieving View Models in anything beyond a simple application. The standard pattern is to have an Interface representing each View Model and then assign the actual class instance at launch by registering it with a Dependency Injection container. This allows you to register your services and view models as long-lived singletons or single-use instances, which can be released once finished.  

Dependency injection frameworks support passing registered types into constructors. When you have a View Model constructor which requires another dependency, the framework will create an instance or pass an existing object when constructing the View Model. It’s beyond the scope of this article to go into Dependency Injection in total, but you could start by looking at the documentation here. 

Binding to a Method

Using the {Binding} syntax allows you to bind properties in your view to properties in your binding source (your View Model). However, it doesn’t allow for more complex scenarios, such as binding to a method that returns a value. In WPF, you could use the ObjectDataProvider helper class to create a binding to a method and specify parameters. As with the constructor scenario, you can use x:Bind to bind to any instance or static method in your code. In addition, you can specify multiple parameters for a function, which goes beyond the methods supported via ICommand for buttons, etc.  

By default, x:Bind uses the OneTime binding mode. This means that the value will be populated once when creating the view and will ignore any further changes. However, you can specify OneWay to allow the value to be recalculated when your View Model supports INotifyPropertyChanged. Where you would typically use the PropertyChanged event to signal that a property value has changed, you can also raise the event with the name of your method; this will cause the x:Bind function to be re-evaluated. 

Because the x:Bind function is evaluated at compilation time, you can use methods that return the expected type for the bound property and avoid the use of IValueConverters. In addition, because x:Bind supports instance and static methods, it can be used to call built-in framework methods to perform string formatting, for example, and to perform multi-binding. 

				
					<TextBlock Grid.Row="4" Grid.Column="1" Text="{x:Bind ViewModel.CalculateDensity(ViewModel.Planet.Mass, ViewModel.Planet.Diameter), Mode=OneWay}"/> 
				
			

Specifying a function that accepts two properties gives you an equivalent to multi-binding. Changes in either of these properties will cause the function to be re-evaluated with the new values. 

One function limitation is that x:Bind will only work with synchronous methods. This is because an asynchronous method will have a return type of Task rather than the T required for your View property. However, it is possible to work around this by writing an additional helper method to wrap an async method.  

				
					public string GetResultOfAsyncMethod() 
        { 
            return AsyncHelpers.RunSync(ViewModel.SimulateLongRunningMethodAsync); 
        } 
				
			

However, when binding to a property, such as TextBlock.Text, a long-running method, would cause a delay in rendering the view. In this case, you would need to use a property instead and have the OnPropertyChanged called when the value changes. 

Binding to functions can be used in both directions too. You specify the BindBack property in your x:Bind statement. This should specify a method that accepts a single argument of the same type that your “getter” method returns. 

Next Steps

You can read more about Uno’s support for the x:Bind syntax here, which follows the WinUI functionality. 

For your convenience, we’ve made the code sample available here. Explore our samples and discover how you can Get Started with Uno Platform to build your desktop, mobile, and web apps. 

FAQs

x:Bind generates optimized code at compile time, eliminating reflection overhead and providing up to 5x faster execution for property access. Traditional Binding uses runtime reflection to resolve property paths, which adds overhead during initial binding and updates. Learn more about x:Bind performance optimizations.

No, x:Bind binds directly to the Page or UserControl’s code-behind by default, not to DataContext. To bind to a View Model, expose it as a property on your Page class or use the x:DataType attribute to specify the type. See Uno Platform’s x:Bind architecture documentation for implementation details.

x:Bind performs null checking at compile time. When binding to potentially null objects, you must use conditional operators or ensure non-null initialization. This compile-time validation prevents runtime null reference exceptions. Microsoft’s documentation on x:Bind and nullable types provides detailed examples.

Enable detailed build output in Visual Studio to see generated binding code. Common issues include missing public accessors, incorrect type specifications, or unsupported binding expressions. The Uno Platform provides specific debugging guidance for x:Bind issues.

Yes, you can use both binding types within the same view. Use x:Bind for performance-critical paths and compile-time validation, while traditional Binding remains useful for dynamic scenarios like DataTemplate content or when binding sources change at runtime. Microsoft’s binding comparison guide details when to use each approach.

Share this post:
Related Posts

Uno Platform 5.2 LIVE Webinar – Today at 3 PM EST – Watch