jpskill.com
🛠️ 開発・MCP コミュニティ

avalonia-data-binding

Avaloniaフレームワークにおけるデータバインディングの様々なパターンを、AIエージェントが理解し活用するための包括的な情報を提供するSkill。

📜 元の英語説明(参考)

Comprehensive guide to data binding patterns in Avalonia for AI agents.

🇯🇵 日本人クリエイター向け解説

一言でいうと

Avaloniaフレームワークにおけるデータバインディングの様々なパターンを、AIエージェントが理解し活用するための包括的な情報を提供するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o avalonia-data-binding.zip https://jpskill.com/download/8809.zip && unzip -o avalonia-data-binding.zip && rm avalonia-data-binding.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/8809.zip -OutFile "$d\avalonia-data-binding.zip"; Expand-Archive "$d\avalonia-data-binding.zip" -DestinationPath $d -Force; ri "$d\avalonia-data-binding.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して avalonia-data-binding.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → avalonia-data-binding フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Avalonia におけるデータバインディング

AI エージェント向けの Avalonia におけるデータバインディングパターンの包括的なガイドです。

私の役割

  • ObservableObject 基底クラスを使用した ViewModel の実装をガイドします
  • [ObservableProperty] 属性を使用して、監視可能なプロパティを作成する方法を示します
  • [RelayCommand] を使用したコマンドパターンを、async および CanExecute を含めて説明します
  • DataTemplate を使用した View-ViewModel マッピング(ナビゲーションに不可欠)を説明します
  • サービスを ViewModel に渡すための依存性注入パターンを示します

活用場面

このスキルは、以下が必要な場合に使用します。

  • Avalonia ビューの新しい ViewModel を作成する
  • UI の変更を通知する監視可能なプロパティを実装する
  • ユーザーインタラクション(ボタンクリックなど)を処理するコマンドを追加する
  • DataTemplate と ContentControl を使用してナビゲーションパターンを設定する

Avalonia におけるデータバインディング

AI エージェント向けの Avalonia におけるデータバインディングパターンの包括的なガイドです。

バインディングモード

OneWay バインディング

<!-- ViewModel のプロパティが UI を更新 -->
<TextBlock Text="{Binding UserName}" />
<TextBlock Text="{Binding UserName, Mode=OneWay}" />  <!-- 明示的 -->

TwoWay バインディング

<!-- UI と ViewModel が同期を維持 -->
<TextBox Text="{Binding UserName, Mode=TwoWay}" />
<Slider Value="{Binding Volume, Mode=TwoWay}" />
<CheckBox IsChecked="{Binding IsEnabled, Mode=TwoWay}" />

ViewModel:

[ObservableProperty]
private string _userName = "";

[ObservableProperty]
private double _volume = 50;

[ObservableProperty]
private bool _isEnabled = true;

OneTime バインディング

<!-- 一度設定すると、更新されない -->
<TextBlock Text="{Binding AppVersion, Mode=OneTime}" />
<Image Source="{Binding StaticImage, Mode=OneTime}" />

OneWayToSource バインディング

<!-- ターゲットがソースを更新するが、その逆はない -->
<TextBox Text="{Binding SearchQuery, Mode=OneWayToSource}" />

各モードの使い分け

以下のように使い分けます。

  • OneWay: 変更頻度の低いデータを表示する場合
  • TwoWay: ユーザー入力コントロール (TextBox, Slider, CheckBox)
  • OneTime: ロード後に変更されない静的データ
  • OneWayToSource: UI が ViewModel を更新するが、その逆はない場合

バインディングパス

単純なプロパティ

<TextBlock Text="{Binding Name}" />
[ObservableProperty]
private string _name = "John";

ネストされたプロパティ

<TextBlock Text="{Binding Person.Address.Street}" />
<TextBlock Text="{Binding User.Profile.Email}" />
[ObservableProperty]
private Person _person = new();

public class Person
{
    public Address Address { get; set; } = new();
}

public class Address
{
    public string Street { get; set; } = "";
}

コレクションインデクサー

<TextBlock Text="{Binding Items[0]}" />
<TextBlock Text="{Binding Users[5].Name}" />
public ObservableCollection<string> Items { get; } = new();
public ObservableCollection<User> Users { get; } = new();

添付プロパティ

<TextBlock Text="{Binding (Grid.Row)}" />
<TextBlock Text="{Binding (DockPanel.Dock)}" />

現在のアイテム

<!-- コレクション内の現在のアイテムにバインド -->
<TextBlock Text="{Binding /}" />
<TextBlock Text="{Binding /Name}" />  <!-- 現在のアイテムのプロパティ -->

バインディングソース

DataContext (デフォルト)

<!-- DataContext にバインド -->
<TextBlock Text="{Binding PropertyName}" />

Element バインディング

<!-- 名前で別の要素にバインド -->
<Slider x:Name="VolumeSlider" Minimum="0" Maximum="100" />
<TextBlock Text="{Binding #VolumeSlider.Value}" />

<!-- 代替構文 -->
<TextBlock Text="{Binding ElementName=VolumeSlider, Path=Value}" />

Relative Source - 親

<!-- 型で先祖を検索 -->
<TextBlock Text="{Binding $parent[Window].Title}" />
<TextBlock Text="{Binding $parent[UserControl].DataContext.PropertyName}" />
<TextBlock Text="{Binding $parent[ListBox].SelectedItem}" />

<!-- 複数レベル -->
<TextBlock Text="{Binding $parent[Grid].$parent[Window].Title}" />

Relative Source - Self

<!-- 自身のプロパティにバインド -->
<TextBlock Text="{Binding $self.Tag}" 
           Tag="Hello" />
<Button Content="{Binding $self.Width}" 
        Width="100" />

Static Resource

<!-- リソースにバインド -->
<TextBlock Text="{StaticResource WelcomeMessage}" />
<Button Background="{DynamicResource ThemeBrush}" />

Static Property

<!-- 静的プロパティにバインド -->
<TextBlock Text="{x:Static local:Constants.AppName}" />
<PathIcon Data="{x:Static icons:Icons.Home}" />

値コンバーター

組み込みコンバーター

Boolean コンバーター

<!-- Not -->
<TextBlock IsVisible="{Binding IsHidden, Converter={x:Static BoolConverters.Not}}" />

<!-- And -->
<Button IsEnabled="{Binding IsValid, Converter={x:Static BoolConverters.And}, ConverterParameter={Binding IsReady}}" />

<!-- Or -->
<Control IsVisible="{Binding ShowA, Converter={x:Static BoolConverters.Or}, ConverterParameter={Binding ShowB}}" />

Object コンバーター

<!-- IsNull -->
<TextBlock IsVisible="{Binding Data, Converter={x:Static ObjectConverters.IsNull}}" />

<!-- IsNotNull -->
<TextBlock IsVisible="{Binding Data, Converter={x:Static ObjectConverters.IsNotNull}}" />

<!-- Equal -->
<RadioButton IsChecked="{Binding SelectedOption, Converter={x:Static ObjectConverters.Equal}, ConverterParameter=Option1}" />

カスタムコンバーター

コンバーターの定義:

public class BoolToColorConverter : IValueConverter
{
    public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        if (value is bool boolValue)
        {
            return boolValue ? Brushes.Green : Brushes.Red;
        }
        return Brushes.Gray;
    }

    public object? ConvertBack(object? va, Type targetType, object? parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

リソースへの登録:

<UserControl.Resources>
    <local:BoolToColorConverter x:Key="BoolToColorConverter" />
</UserControl.Resources>

(原文がここで切り詰められています)

📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Data Binding in Avalonia

Comprehensive guide to data binding patterns in Avalonia for AI agents.

What I do

  • Guide implementation of ViewModels with ObservableObject base class
  • Show how to create observable properties with [ObservableProperty] attribute
  • Demonstrate command patterns with [RelayCommand] including async and CanExecute
  • Explain View-ViewModel mapping using DataTemplates (critical for navigation)
  • Show dependency injection patterns for passing services to ViewModels

When to use me

Use this skill when you need to:

  • Create new ViewModels for Avalonia views
  • Implement observable properties that notify the UI of changes
  • Add commands to handle user interactions (button clicks, etc.)
  • Set up navigation patterns with DataTemplates and ContentControl

Data Binding in Avalonia

Comprehensive guide to data binding patterns in Avalonia for AI agents.

Binding Modes

OneWay Binding

<!-- ViewModel property updates UI -->
<TextBlock Text="{Binding UserName}" />
<TextBlock Text="{Binding UserName, Mode=OneWay}" />  <!-- Explicit -->

TwoWay Binding

<!-- UI and ViewModel stay synchronized -->
<TextBox Text="{Binding UserName, Mode=TwoWay}" />
<Slider Value="{Binding Volume, Mode=TwoWay}" />
<CheckBox IsChecked="{Binding IsEnabled, Mode=TwoWay}" />

ViewModel:

[ObservableProperty]
private string _userName = "";

[ObservableProperty]
private double _volume = 50;

[ObservableProperty]
private bool _isEnabled = true;

OneTime Binding

<!-- Set once, never updates -->
<TextBlock Text="{Binding AppVersion, Mode=OneTime}" />
<Image Source="{Binding StaticImage, Mode=OneTime}" />

OneWayToSource Binding

<!-- Target updates source, but not vice versa -->
<TextBox Text="{Binding SearchQuery, Mode=OneWayToSource}" />

When to use each

Use:

  • OneWay: Display data that changes infrequently
  • TwoWay: User input controls (TextBox, Slider, CheckBox)
  • OneTime: Static data that won't change after load
  • OneWayToSource: When UI updates ViewModel but not the other way

Binding Paths

Simple Property

<TextBlock Text="{Binding Name}" />
[ObservableProperty]
private string _name = "John";

Nested Property

<TextBlock Text="{Binding Person.Address.Street}" />
<TextBlock Text="{Binding User.Profile.Email}" />
[ObservableProperty]
private Person _person = new();

public class Person
{
    public Address Address { get; set; } = new();
}

public class Address
{
    public string Street { get; set; } = "";
}

Collection Indexer

<TextBlock Text="{Binding Items[0]}" />
<TextBlock Text="{Binding Users[5].Name}" />
public ObservableCollection<string> Items { get; } = new();
public ObservableCollection<User> Users { get; } = new();

Attached Property

<TextBlock Text="{Binding (Grid.Row)}" />
<TextBlock Text="{Binding (DockPanel.Dock)}" />

Current Item

<!-- Bind to current item in collection -->
<TextBlock Text="{Binding /}" />
<TextBlock Text="{Binding /Name}" />  <!-- Property of current item -->

Binding Sources

DataContext (Default)

<!-- Binds to DataContext -->
<TextBlock Text="{Binding PropertyName}" />

Element Binding

<!-- Bind to another element by name -->
<Slider x:Name="VolumeSlider" Minimum="0" Maximum="100" />
<TextBlock Text="{Binding #VolumeSlider.Value}" />

<!-- Alternative syntax -->
<TextBlock Text="{Binding ElementName=VolumeSlider, Path=Value}" />

Relative Source - Parent

<!-- Find ancestor by type -->
<TextBlock Text="{Binding $parent[Window].Title}" />
<TextBlock Text="{Binding $parent[UserControl].DataContext.PropertyName}" />
<TextBlock Text="{Binding $parent[ListBox].SelectedItem}" />

<!-- Multiple levels -->
<TextBlock Text="{Binding $parent[Grid].$parent[Window].Title}" />

Relative Source - Self

<!-- Bind to own property -->
<TextBlock Text="{Binding $self.Tag}" 
           Tag="Hello" />
<Button Content="{Binding $self.Width}" 
        Width="100" />

Static Resource

<!-- Bind to resource -->
<TextBlock Text="{StaticResource WelcomeMessage}" />
<Button Background="{DynamicResource ThemeBrush}" />

Static Property

<!-- Bind to static property -->
<TextBlock Text="{x:Static local:Constants.AppName}" />
<PathIcon Data="{x:Static icons:Icons.Home}" />

Value Converters

Built-in Converters

Boolean Converters

<!-- Not -->
<TextBlock IsVisible="{Binding IsHidden, Converter={x:Static BoolConverters.Not}}" />

<!-- And -->
<Button IsEnabled="{Binding IsValid, Converter={x:Static BoolConverters.And}, ConverterParameter={Binding IsReady}}" />

<!-- Or -->
<Control IsVisible="{Binding ShowA, Converter={x:Static BoolConverters.Or}, ConverterParameter={Binding ShowB}}" />

Object Converters

<!-- IsNull -->
<TextBlock IsVisible="{Binding Data, Converter={x:Static ObjectConverters.IsNull}}" />

<!-- IsNotNull -->
<TextBlock IsVisible="{Binding Data, Converter={x:Static ObjectConverters.IsNotNull}}" />

<!-- Equal -->
<RadioButton IsChecked="{Binding SelectedOption, Converter={x:Static ObjectConverters.Equal}, ConverterParameter=Option1}" />

Custom Converter

Define Converter:

public class BoolToColorConverter : IValueConverter
{
    public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        if (value is bool boolValue)
        {
            return boolValue ? Brushes.Green : Brushes.Red;
        }
        return Brushes.Gray;
    }

    public object? ConvertBack(object? va, Type targetType, object? parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Register in Resources:

<UserControl.Resources>
    <local:BoolToColorConverter x:Key="BoolToColorConverter" />
</UserControl.Resources>

Use Converter:

<TextBlock Foreground="{Binding IsActive, Converter={StaticResource BoolToColorConverter}}" />

Converter with Parameter

<TextBlock Text="{Binding Value, 
                          Converter={StaticResource NumberToStringConverter}, 
                          ConverterParamet
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
    if (value is double number && parameter is string decimals)
    {
        return number.ToString($"F{decimals}");
    }
    return value?.ToString();
}

String Formatting

Basic Formatting

<!-- Number formatting -->
<TextBlock Text="{Binding Price, StringFormat='${0:F2}'}" />
<!-- Output: $19.99 -->

<TextBlock Text="{Binding Count, StringFormat='{}{0} items'}" />
<!-- Output: 5 items (note: {} escapes the opening brace) -->

<!-- Date formatting -->
<TextBlock Text="{Binding Date, StringForma{0:yyyy-MM-dd}'}" />
<!-- Output: Date: 2024-01-23 -->

<TextBlock Text="{Binding Time, StringFormat='{0:HH:mm:ss}'}" />
<!-- Output: 14:30:45 -->

Format Specifiers

Numeric Formats

<!-- Currency -->
<TextBlock Text="{Binding Amount, StringFormat='{}{0:C}'}" />
<!-- $1,234.56 -->

<!-- Fixed-point -->
<TextBlock Text="{Binding Value, StringFormat='{}{0:F2}'}" />
<!-- 123.46 -->

<!-- Number with separators -->
<TextBlock Text="{Binding Count, StringFormat='{}{0:N0}'}" />
<!-- 1,234 -->

<!-- Percentage -->
<TextBlock Text="{Binding Ratio, StringFormat='{}{0:P1}'}" />
<!-- 45.6% -->

<!-- Hexadecimal -->
<TextBlock Text="{Binding ColorValue, StringFormat='{}{0:X6}'}" />
<!-- FF00AA -->

Date/Time Formats

<!-- Short date -->
<TextBlock Text="{Binding Date, StringFormat='{}{0:d}'}" />
<!-- 1/23/2024 -->

<!-- Long date -->
<TextBlock Text="{Binding Date, StringFormat='{}{0:D}'}" />
<!-- Tuesday, January 23, 2024 -->

<!-- Custom date -->
<TextBlock Text="{Binding Date, StringFormat='{}{0:MMM dd, yyyy}'}" />
<!-- Jan 23, 2024 -->

<!-- Time -->
<TextBlock Text="{Binding Time, StringFormat='{}{0:t}'}" />
<!-- 2:30 PM -->

<!-- Date and time -->
<TextBlock Text="{Binding DateTime, StringFormat='{}{0:g}'}" />
<!-- 1/23/2024 2:30 PM -->

Escaping Braces

<!-- Need {} to escape opening brace -->
<TextBlock Text="{Binding Count, StringFormat='{}{0} items'}" />

<!-- Without escape (error) -->
<TextBlock Text="{Binding Count, StringFormat='{0} items'}" />  <!-- ❌ -->

Compiled Bindings

Why Compiled Bindings?

  • Performance: 2-3x faster than reflection-based bindings
  • Type Safety: Compile-time errors instead of runtime
  • IntelliSense: Better IDE support
  • Required: For Avalon with AvaloniaUseCompiledBindingsByDefault

Enabling Compiled Bindings

Project File:

<PropertyGroup>
    <AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>

AXAML:

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:vm="using:YourApp.ViewModels"
             x:DataType="vm:YourViewModel">  <!-- Required! -->

    <TextBlock Text="{Binding PropertyName}" />  <!-- Compiled -->
</UserControl>

Compiled Binding Syntax

<!-- Standard binding (compiled if x:DataType is set) -->
<TextBlock Text="{Binding Name}" />

<!-- Explicit compiled binding -->
<TextBlock Text="{CompiledBinding Name}" />

<!-- Reflection binding (opt-out) -->
<TextBlock Text="{ReflectionBinding Name}" />

DataType for Collections

<ItemsControl ItemsSource="{Binding People}">
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="vm:PersonViewModel">
            <!-- Compiled bindings for PersonViewModel -->
            <TextBlock Text="{Binding Name}" />
            <TextBlock Text="{Binding Age}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

DataType Inheritance

<UserControl x:DataType="vm:MainViewModel">
    <!-- Binds to MainViewModel -->
    <TextBlock Text="{Binding Title}" />

    <ContentControl Content="{Binding ChildViewModel}">
        <ContentControl.ContentTemplate>
            <DataTemplate x:DataType="vm:ChildViewModel">
                <!-- Binds to ChildViewModel -->
                <TextBlock Text="{Binding ChildProperty}" />
            </DataTemplate>
        </ContentControl.ContentTemplate>
    </ContentControl>
</UserControl>

Common Patterns

Binding to Commands```xml

<Button Content="Save" Command="{Binding SaveCommand}" /> <Button Content="Delete" Command="{Binding DeleteCommand}" CommandParameter="{Binding SelectedItem}" />

```csharp
[RelayCommand]
private void Save()
{
    // Save logic
}

[RelayCommand]
private void Delete(object? parameter)
{
    if (parameter is Item item)
    {
        // Delete item
    }
}

Binding to Collections

<!-- ItemsControl -->
<ItemsControl ItemsSource="{Binding Items}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Name}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

<!-- ListBox with selection -->
<ListBox ItemsSource="{Binding Items}"
         SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />

<!-- DataGrid -->
<DataGrid ItemsSource="{Binding People}"
          SelectedItem="{Binding SelectedPerson, Mode=TwoWay}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
        <DataGridTextColumn Header="Age" Binding="{Binding Age}" />
    </DataGrid.Columns>
</DataGrid>
public ObservableCollection<Item> Items { get; } = new();

[ObservableProperty]
private Item? _selectedItem;

Binding to Enums

<!-- ComboBox with enum -->
<ComboBox ItemsSource="{Binding AllStatuses}"
          SelectedItem="{Binding CurrentStatus, Mode=TwoWay}" />
public enum Status { Active, Inactive, Pending }

public IEnumerable<Status> AllStatuses => Enum.GetValues<Status>();

[ObservableProperty]
private Status _currentStatus = Status.Active;

Conditional Visibility

<!-- Show/hide based on boolean -->
<TextBlock Text="Loading..." 
           IsVisible="{Binding IsLoading}" />

<!-- Show when NOT loading -->
<TextBlock Text="Content" 
           IsVisible="{Binding IsLoading, Converter={x:Static BoolConverters.Not}}" />

<!-- Show when data exists -->
<TextBlock Text="No data" 
           IsVisible="{Binding Data, Converter={x:Static ObjectConverters.IsNull}}" />

Multi-Binding (Alternative Approaches)

Option 1: Computed Property

[ObservableProperty]
private string _firstName = "";

[ObservableProperty]
private string _lastName = "";

public string FullName => $"{FirstName} {LastName}";

partial void OnFirstNameChanged(string value) => OnPropertyChanged(nameof(FullName));
partial void OnLastNameChanged(string value) => OnPropertyChanged(nameof(FullName));
<TextBlock Text="{Binding FullName}" />

Option 2: Converter

<TextBlock>
    <TextBlock.Text>
        <MultiBinding Converter="{StaticResource FullNameConverter}">
            <Binding Path="FirstName" />
            <Binding Path="LastName" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

Binding with Fallback

<!-- Show fallback if binding fails -->
<TextBlock Text="{Binding Name, FallbackValue='Unknown'}" />
<TextBlock Text="{Binding Age, FallbackValue=0}" />
<Image Source="{Binding ImagePath, FallbackValue='/Assets/placeholder.png'}" />

Binding with TargetNullValue

<!-- Show specific value when source is null -->
<TextBlock Text="{Binding Description, TargetNullValue='No description'}" />
<TextBlock Text="{Binding Count, TargetNullValue=0}" />

Best Practices

  1. Always set x:DataType for compiled bindings
  2. Use TwoWay explicitly for input controls
  3. **Use OneTimetic data to improve performance
  4. Prefer computed properties over complex converters
  5. Use StringFormat for simple formatting
  6. Use converters for complex transformations
  7. Bind to commands instead of event handlers
  8. Use ObservableCollection for dynamic lists
  9. Implement INotifyPropertyChanged (via CommunityToolkit.Mvvm)
  10. Test bindings with design-time data

Common Mistakes

DatePicker Binding Type Mismatch

[ObservableProperty]
private DateTime _selectedDate = DateTime.Now; // ❌ InvalidCastException

Correct

[ObservableProperty]
private DateTimeOffset? _selectedDate = DateTimeOffset.Now; // ✅ Use DateTimeOffset?

Missing Mode for input

<TextBox Text="{Binding Name}" />  <!-- OneWay by default -->

Correct

<TextBox Text="{Binding Name, Mode=TwoWay}" />

Forgetting x:DataType

<UserControl x:Class="MyView">
    <TextBlock Text="{Binding Name}" />  <!-- Reflection binding -->
</UserControl>

Correct

<UserControl x:Class="MyView" x:DataType="vm:MyViewModel">
    <TextBlock Text="{Binding Name}" />  <!-- Compiled binding -->
</UserControl>

Not notifying property changes

private string _name;
public string Name
{
    get => _name;
    set => _name = value;  // UI won't update!
}

Correct

[ObservableProperty]
private string _name = "";  // Generates proper notification