Install
$ agentstack add skill-dotnet-skills-maui-data-binding ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
.NET MAUI Data Binding
Wire UI controls to ViewModel properties with compile-time safety, correct change notification, and minimal overhead. Prefer compiled bindings everywhere and treat binding warnings as build errors.
When to Use
- Adding
x:DataTypecompiled bindings to a new or existing page - Implementing
INotifyPropertyChangedor CommunityToolkitObservableObject - Creating or consuming
IValueConverter/IMultiValueConverter - Choosing the correct
BindingModefor a control property - Setting
BindingContextin XAML or code-behind - Using relative bindings (
Self,AncestorType,TemplatedParent) - Applying
StringFormat,FallbackValue, orTargetNullValue - Writing AOT-safe code bindings with
SetBindingand lambdas (.NET 9+)
When Not to Use
- CollectionView layouts / templates — use the
maui-collectionviewskill - Shell navigation parameters — use the
maui-shell-navigationskill - Service registration / DI — use the
maui-dependency-injectionskill - Property-change-triggered animations — use built-in .NET MAUI animation APIs
Inputs
- A .NET MAUI project targeting .NET 8 or later
- XAML pages or C# code-behind where bindings are declared
- A ViewModel class (or plan to create one)
Compiled Bindings — x:DataType Placement
Compiled bindings are 8–20× faster than reflection-based bindings and are required for NativeAOT / trimming. Enable them with x:DataType.
Placement rules
Set x:DataType only where BindingContext is set:
- Page / View root — where you assign
BindingContext. - DataTemplate — which creates a new binding scope.
Do not scatter x:DataType on arbitrary child elements. Adding x:DataType="x:Object" on children to escape compiled bindings is an anti-pattern — it disables compile-time checking and reintroduces reflection.
DataTemplate always needs its own x:DataType
Enforce binding warnings as errors
| Warning | Meaning | |---------|---------| | XC0022 | Binding path not found on the declared x:DataType | | XC0023 | Property is not bindable | | XC0024 | x:DataType type not found | | XC0025 | Binding used without x:DataType (non-compiled fallback) |
Add to the .csproj:
XC0022;XC0025
Binding Modes
Set Mode explicitly only when overriding the default. Most properties already have the correct default:
| Mode | Direction | Use case | |------|-----------|----------| | OneWay | Source → Target | Display-only (default for most properties) | | TwoWay | Source ↔ Target | Editable controls (Entry.Text, Switch.IsToggled) | | OneWayToSource | Target → Source | Read user input without pushing back to UI | | OneTime | Source → Target (once) | Static values; no change-tracking overhead |
BindingContext and Property Paths
Every BindableObject inherits BindingContext from its parent unless explicitly set. Property paths support dot notation and indexers:
Set BindingContext in XAML:
Or in code-behind (preferred with DI):
public MainPage(MainViewModel vm)
{
InitializeComponent();
BindingContext = vm;
}
INotifyPropertyChanged and ObservableObject
Manual implementation
public class MainViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
private string _title = string.Empty;
public string Title
{
get => _title;
set
{
if (_title != value)
{
_title = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
}
}
}
}
CommunityToolkit.Mvvm (recommended)
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
public partial class MainViewModel : ObservableObject
{
[ObservableProperty]
private string _title = string.Empty;
[RelayCommand]
private async Task LoadDataAsync() { /* ... */ }
}
The source generator creates the Title property, PropertyChanged raise, and LoadDataCommand automatically.
Value Converters — IValueConverter
Implement Convert (source → target) and ConvertBack (target → source):
public class IntToBoolConverter : IValueConverter
{
public object? Convert(object? value, Type targetType,
object? parameter, CultureInfo culture)
=> value is int i && i != 0;
public object? ConvertBack(object? value, Type targetType,
object? parameter, CultureInfo culture)
=> value is true ? 1 : 0;
}
Declare in XAML resources and consume:
ConverterParameter is always passed as a string — parse inside Convert:
Multi-Binding
Combine multiple source values with IMultiValueConverter:
public class FullNameConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType,
object parameter, CultureInfo culture)
{
if (values.Length == 2 && values[0] is string first
&& values[1] is string last)
return $"{first} {last}";
return string.Empty;
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
Relative Bindings
| Source | Syntax | Use case | |--------|--------|----------| | Self | {Binding Source={RelativeSource Self}, Path=WidthRequest} | Bind to own properties | | Ancestor | {Binding BindingContext.Title, Source={RelativeSource AncestorType={x:Type ContentPage}}} | Reach parent BindingContext | | TemplatedParent | {Binding Source={RelativeSource TemplatedParent}, Path=Padding} | Inside ControlTemplate |
StringFormat
Use Binding.StringFormat for simple display formatting without a converter:
Wrap the format string in single quotes when it contains commas or braces.
Binding Fallbacks
- FallbackValue — used when the binding path cannot be resolved or the
converter throws.
- TargetNullValue — used when the bound value is
null.
.NET 9+ Code Bindings (AOT-safe)
Fully AOT-safe, no reflection:
label.SetBinding(Label.TextProperty,
static (PersonViewModel vm) => vm.FullName);
entry.SetBinding(Entry.TextProperty,
static (PersonViewModel vm) => vm.Age,
mode: BindingMode.TwoWay,
converter: new IntToStringConverter());
Threading
MAUI automatically marshals PropertyChanged to the UI thread — you can raise it from any thread. However, direct ObservableCollection mutations (Add / Remove) from background threads may crash:
// ✅ Safe — PropertyChanged is auto-marshalled
await Task.Run(() => Title = "Loaded");
// ⚠️ ObservableCollection.Add — dispatch to UI thread
MainThread.BeginInvokeOnMainThread(() => Items.Add(newItem));
Common Pitfalls
| Mistake | Fix | |---------|-----| | Missing x:DataType — bindings silently fall back to reflection | Add x:DataType at page root and every DataTemplate; enable XC0025 as error | | Forgetting to set BindingContext | Set in XAML (`) or inject via constructor | | Specifying redundant Mode=OneWay / Mode=TwoWay | Omit Mode when using the control's default | | ViewModel does not implement INotifyPropertyChanged | Use ObservableObject from CommunityToolkit.Mvvm or implement manually | | Mutating ObservableCollection off the UI thread | Wrap mutations in MainThread.BeginInvokeOnMainThread | | Complex converter chains in hot paths | Pre-compute values in the ViewModel instead | | Using x:DataType="x:Object" to escape compiled bindings | Restructure bindings; keep compile-time safety | | Binding to non-public properties | Binding targets must be public` properties (fields are ignored) |
References
- Data binding overview
- Compiled bindings
- Value converters
- Relative bindings
- Multi-bindings
- CommunityToolkit.Mvvm
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: dotnet
- Source: dotnet/skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.