AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Maui Data Binding

skill-dotnet-skills-maui-data-binding · by dotnet

>-

No reviews yet
0 installs
4 views
0.0% view→install

Install

$ agentstack add skill-dotnet-skills-maui-data-binding

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No 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.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-dotnet-skills-maui-data-binding)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

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 →
Are you the author of Maui Data Binding? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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:DataType compiled bindings to a new or existing page
  • Implementing INotifyPropertyChanged or CommunityToolkit ObservableObject
  • Creating or consuming IValueConverter / IMultiValueConverter
  • Choosing the correct BindingMode for a control property
  • Setting BindingContext in XAML or code-behind
  • Using relative bindings (Self, AncestorType, TemplatedParent)
  • Applying StringFormat, FallbackValue, or TargetNullValue
  • Writing AOT-safe code bindings with SetBinding and lambdas (.NET 9+)

When Not to Use

  • CollectionView layouts / templates — use the maui-collectionview skill
  • Shell navigation parameters — use the maui-shell-navigation skill
  • Service registration / DI — use the maui-dependency-injection skill
  • 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:

  1. Page / View root — where you assign BindingContext.
  2. 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

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.