Learn about compiled bindings in .NET MAUI and how they affect performance and debugging.
Imagine you’re about to buy a house … but you can only discover its defects once you’re already living in it.
You’d definitely want to know that information beforehand to make better decisions, right? ️
The same thing happens in applications: depending on the mechanism we choose, some processes can be slower, consume more resources and—even worse—show errors way too late.
Today, you’ll learn what Compiled Bindings are and the latest enhancements available in .NET MAUI to boost performance and avoid unpleasant surprises when the app is already in the users’ hands.
Data Bindings in .NET MAUI
In .NET MAUI, we usually work with data bindings, but when using them, it’s important to keep two key points in mind:
There’s no compile-time validation of binding expressions, which means that if a binding is invalid, we’ll only find out when the app is already running. This can cost us valuable time, when we could have detected the issue during the compilation process.
And another point, related to the one above, is that runtime verification bindings aren’t very efficient in terms of performance, since they do all their work while the app is running. To “check” the information they need, they must inspect objects over and over again. This makes the process slower and, of course, increases resource consumption.
Compiled bindings enhance the performance of data bindings in .NET MAUI by resolving binding expressions during compile time instead of waiting until the app is running. This allows the system to detect issues early, so if a binding is incorrect, it will show up as a build error. As a result, debugging becomes easier and you avoid dealing with unexpected binding failures at runtime.
Compile Time vs. Runtime
We’ve been talking a lot about compile time and runtime, so if those terms still feel a bit blurry for you, here’s a simple explanation to make everything clearer.
➖ Compile Time: This is the moment when your code is checked to make sure everything is correct before the app can run. Here is where issues like typos in property names, missing variables, or incompatible types are detected. If something is wrong, the build stops and alerts you so you can fix it first. This saves a lot of headaches—it’s always better to catch errors at this stage rather than later on.
➖ Runtime: This occurs when the app is already running. If an error appears at this point, it can definitely be fixed—but it may take a bit more time, since you often need to analyze more carefully to understand exactly what caused the issue. And worst of all, it can crash or freeze the app right in front of the user.
Summarizing it in a table, these would be the differences between the two:

Ways to Use Compiled Bindings
There are two ways to use compiled bindings in .NET MAUI: you can apply them directly in your XAML files or configure them through C# code.
Let’s explore each one of them:
Compiled Bindings in XAML
In .NET MAUI 8, compiled bindings aren’t applied when a XAML binding uses the Source property, and they also don’t support multi-bindings.
Starting in .NET MAUI 9, the compiler now shows warnings when bindings aren’t using compiled bindings by default. You can learn more about this behavior in the article: XAML compiled binding warnings.
Compiled Bindings in C# Code
Working with compiled bindings brings many benefits. One of the biggest ones—besides performance improvements—is that it gives us a much better experience as developers. It saves us a lot of time by showing problems before running the application. Otherwise, we would have to debug, investigate exactly where the issue happens, identify the error and then fix it. Now, IntelliSense can warn us right away.
When using bindings on C#, we normally rely on string-based property paths, such as "Text".
These paths are resolved at runtime using reflection, and that process consumes resources. On top of that, the performance cost can vary depending on the platform where the app is running (Android, iOS, Windows, etc.).
Example:
// .NET 8
MyLabel.SetBinding(Label.TextProperty, "Text");
Now, in .NET MAUI 9, a new SetBinding extension method was introduced that allows defining bindings using a lambda expression (Func) instead of a string.
Like this:
// .NET 9
MyLabel.SetBinding(Label.TextProperty, static (Entry entry) => entry.Text);
When using SetBinding, you need to be careful with the lambda expressions you define. Only simple property access expressions are allowed. This is because compiled bindings need to know exactly which property is being bound in order to generate the optimized binding code at compile time.
A valid example would be directly accessing the Name property:
static (PersonViewModel vm) => vm.Name;
Besides property access, you can also use:
Array or list index access
static (PersonViewModel vm) => vm.PhoneNumbers[0];
Indexer access ([])
static (PersonViewModel vm) => vm.Config["Font"];
Casts to access the correct property
static (Label label) => (label.BindingContext as PersonViewModel).Name;
static (Label label) => ((PersonViewModel)label.BindingContext).Name;
❌ What is not allowed?
Just as it’s important to know what is supported, it’s equally important to understand what isn’t. Here are some examples:
➖ Method calls
static (PersonViewModel vm) => vm.GetAddress();
➖ Creating new values by combining multiple properties
static (PersonViewModel vm) => vm.Address?.Street + " " + vm.Address?.City;
➖ String interpolation
static (PersonViewModel vm) => $"Name: {vm.Name}";
BindingBase.Create
Another improvement in .NET MAUI 9 is BindingBase.Create.
In addition to using lambda expressions directly with SetBinding, .NET MAUI 9 also adds a helper called BindingBase.Create. This is useful for more complex bindings, such as a MultiBinding.
Example:
.NET 8
myEntry.SetBinding(Entry.TextProperty, new MultiBinding
{
Bindings = new Collection<BindingBase>
{
new Binding(nameof(Entry.FontFamily), source: RelativeBindingSource.Self),
new Binding(nameof(Entry.FontSize), source: RelativeBindingSource.Self),
new Binding(nameof(Entry.FontAttributes), source: RelativeBindingSource.Self),
},
Converter = new StringConcatenationConverter()
});
Now in .NET 9
// in .NET 9
myEntry.SetBinding(Entry.TextProperty, new MultiBinding
{
Bindings = new Collection<BindingBase>
{
Binding.Create(static (Entry entry) => entry.FontFamily, source: RelativeBindingSource.Self),
Binding.Create(static (Entry entry) => entry.FontSize, source: RelativeBindingSource.Self),
Binding.Create(static (Entry entry) => entry.FontAttributes, source: RelativeBindingSource.Self),
},
Converter = new StringConcatenationConverter()
});
Compiler Error
⚠️ Important: The official documentation says: “A CS0272 compiler error will occur if the set accessor for a property or indexer is inaccessible. If this occurs, increase the accessibility of the accessor.”
Let’s understand it in a simpler way.
This error may appear when you try to assign a value to a property or indexer, but its set accessor isn’t accessible. For example:
public string Name { get; private set; }
Here, the Name property can be read, but the set is private—so if you try to assign a value, it won’t be possible:
person.Name = "Leo"; // ❌ CS0272
And what would be the solution to avoid a CS0272 error? Just change the accessibility of the set so that it can be modified when needed, for example:
public string Name { get; set; } // ✅ Now it can be updated
Conclusion
And that’s it! Now you know what compiled bindings are, why they matter for performance and debugging, and how to use them in C#—including the enhancements introduced in .NET MAUI 9.
By applying compiled bindings, your apps become faster, more reliable and much easier to troubleshoot … before your users ever see an error. I hope this guide helps you improve the quality and performance of your applications starting today!
If you have any questions or want to see more related topics, feel free to leave them in the comments—I’d love to help you!
See you in the next article! ♀️
References
The explanation was based on the official documentation, and includes most of the code examples presented there.