avalonia-data-binding
Comprehensive guide to data binding patterns in Avalonia for AI agents.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Comprehensive guide to data binding patterns in Avalonia for AI agents.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Implement MVVM patterns using CommunityToolkit.Mvvm in Avalonia applications with ViewModels, Commands, and Dependency Injection
Quick reference for Avalonia XAML (AXAML) syntax including namespaces, property syntax, bindings, styles, and SukiUI patterns
A guide on working with claims in asp.net core
Guides agents on implmenting policy based authorization in Asp.net
| name | avalonia-data-binding |
| description | Comprehensive guide to data binding patterns in Avalonia for AI agents. |
| license | MIT |
| compatibility | opencode |
| metadata | {"audience":"avalonia-developers","framework":"avalonia"} |
Comprehensive guide to data binding patterns in Avalonia for AI agents.
Use this skill when you need to:
Comprehensive guide to data binding patterns in Avalonia for AI agents.
<!-- ViewModel property updates UI -->
<TextBlock Text="{Binding UserName}" />
<TextBlock Text="{Binding UserName, Mode=OneWay}" /> <!-- Explicit -->
<!-- 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;
<!-- Set once, never updates -->
<TextBlock Text="{Binding AppVersion, Mode=OneTime}" />
<Image Source="{Binding StaticImage, Mode=OneTime}" />
<!-- Target updates source, but not vice versa -->
<TextBox Text="{Binding SearchQuery, Mode=OneWayToSource}" />
Use:
<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)}" />
<!-- Bind to current item in collection -->
<TextBlock Text="{Binding /}" />
<TextBlock Text="{Binding /Name}" /> <!-- Property of current item -->
<!-- Binds to DataContext -->
<TextBlock Text="{Binding PropertyName}" />
<!-- 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}" />
<!-- 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}" />
<!-- Bind to own property -->
<TextBlock Text="{Binding $self.Tag}"
Tag="Hello" />
<Button Content="{Binding $self.Width}"
Width="100" />
<!-- Bind to resource -->
<TextBlock Text="{StaticResource WelcomeMessage}" />
<Button Background="{DynamicResource ThemeBrush}" />
<!-- Bind to static property -->
<TextBlock Text="{x:Static local:Constants.AppName}" />
<PathIcon Data="{x:Static icons:Icons.Home}" />
<!-- 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}}" />
<!-- 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}" />
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}}" />
<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();
}
<!-- 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 -->
<!-- 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 -->
<!-- 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 -->
<!-- Need {} to escape opening brace -->
<TextBlock Text="{Binding Count, StringFormat='{}{0} items'}" />
<!-- Without escape (error) -->
<TextBlock Text="{Binding Count, StringFormat='{0} items'}" /> <!-- ❌ -->
AvaloniaUseCompiledBindingsByDefaultProject 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>
<!-- 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}" />
<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>
<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>
```csharp
[RelayCommand]
private void Save()
{
// Save logic
}
[RelayCommand]
private void Delete(object? parameter)
{
if (parameter is Item item)
{
// Delete item
}
}
<!-- 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;
<!-- 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;
<!-- 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}}" />
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>
<!-- 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'}" />
<!-- Show specific value when source is null -->
<TextBlock Text="{Binding Description, TargetNullValue='No description'}" />
<TextBlock Text="{Binding Count, TargetNullValue=0}" />
❌ 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