maui-data-binding
Guidance for .NET MAUI XAML and C# data bindings — compiled bindings, INotifyPropertyChanged / ObservableObject, value converters, binding modes, multi-binding, relative bindings, fallbacks, and MVVM best practices. USE FOR: setting up compiled bindings with x:DataType, implementing INotifyPropertyChanged or CommunityToolkit ObservableObject, creating IValueConverter / IMultiValueConverter, choosing binding modes, configuring BindingContext, relative bindings, binding fallbacks, StringFormat, code-behind SetBinding with lambdas, and enforcing XC0022/XC0025 warnings. DO NOT USE FOR: CollectionView item templates and layouts (use maui-collectionview), Shell navigation data passing (use maui-shell-navigation), dependency injection (use maui-dependency-injection), or animations triggered by property changes (use .NET MAUI animation APIs).
What this skill does
# .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](https://learn.microsoft.com/dotnet/maui/user-interface/animation/basic)
## 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.
```xml
<!-- ✅ Correct: x:DataType at the page root -->
<ContentPage xmlns:vm="clr-namespace:MyApp.ViewModels"
x:DataType="vm:MainViewModel">
<StackLayout>
<Label Text="{Binding Title}" />
<Slider Value="{Binding Progress}" />
</StackLayout>
</ContentPage>
<!-- ❌ Wrong: x:DataType scattered on children -->
<ContentPage x:DataType="vm:MainViewModel">
<StackLayout>
<Label Text="{Binding Title}" />
<Slider x:DataType="x:Object" Value="{Binding Progress}" />
</StackLayout>
</ContentPage>
```
### DataTemplate always needs its own x:DataType
```xml
<CollectionView ItemsSource="{Binding People}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:Person">
<Label Text="{Binding FullName}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
```
### 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`:
```xml
<WarningsAsErrors>XC0022;XC0025</WarningsAsErrors>
```
---
## 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 |
```xml
<!-- ✅ Defaults — omit Mode -->
<Label Text="{Binding Score}" />
<Entry Text="{Binding UserName}" />
<Switch IsToggled="{Binding DarkMode}" />
<!-- ✅ Override only when needed -->
<Label Text="{Binding Title, Mode=OneTime}" />
<Entry Text="{Binding SearchQuery, Mode=OneWayToSource}" />
<!-- ❌ Redundant — adds noise -->
<Label Text="{Binding Score, Mode=OneWay}" />
<Entry Text="{Binding UserName, Mode=TwoWay}" />
```
---
## BindingContext and Property Paths
Every `BindableObject` inherits `BindingContext` from its parent unless
explicitly set. Property paths support dot notation and indexers:
```xml
<Label Text="{Binding Address.City}" />
<Label Text="{Binding Items[0].Name}" />
```
Set `BindingContext` in XAML:
```xml
<ContentPage xmlns:vm="clr-namespace:MyApp.ViewModels"
x:DataType="vm:MainViewModel">
<ContentPage.BindingContext>
<vm:MainViewModel />
</ContentPage.BindingContext>
</ContentPage>
```
Or in code-behind (preferred with DI):
```csharp
public MainPage(MainViewModel vm)
{
InitializeComponent();
BindingContext = vm;
}
```
---
## INotifyPropertyChanged and ObservableObject
### Manual implementation
```csharp
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)
```csharp
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):
```csharp
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:
```xml
<ContentPage.Resources>
<local:IntToBoolConverter x:Key="IntToBool" />
</ContentPage.Resources>
<Switch IsToggled="{Binding Count, Converter={StaticResource IntToBool}}" />
```
`ConverterParameter` is always passed as a **string** — parse inside `Convert`:
```xml
<Label Text="{Binding Score, Converter={StaticResource ThresholdConverter},
ConverterParameter=50}" />
```
---
## Multi-Binding
Combine multiple source values with `IMultiValueConverter`:
```xml
<Label>
<Label.Text>
<MultiBinding Converter="{StaticResource FullNameConverter}">
<Binding Path="FirstName" />
<Binding Path="LastName" />
</MultiBinding>
</Label.Text>
</Label>
```
```csharp
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}, PathRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.