avalonia-property-system
Skill50 starsChanged 9 days agoMITView on GitHub
Use when working with Avalonia's property system: StyledProperty, DirectProperty, AttachedProperty, property inheritance, metadata override, coercion, value priority, or observing property changes via GetObservable or OnPropertyChanged.
In this repository23 other files it gives its agents.
- avalonia-app-developmentSkill
- avalonia-controlsSkill
- avalonia-custom-controlsSkill
- avalonia-data-bindingSkill
- avalonia-data-templatesSkill
- avalonia-deploymentSkill
- avalonia-eventsSkill
- avalonia-graphics-animationSkill
- avalonia-input-interactionSkill
- avalonia-interop-renderingSkill
- avalonia-layoutSkill
- avalonia-mobileSkill
- avalonia-mvvmSkill
- avalonia-performanceSkill
- avalonia-pro-maxSkill
- avalonia-servicesSkill
- avalonia-stylingSkill
- avalonia-testingSkill
- avalonia-threadingSkill
- avalonia-versionsSkill
- avalonia-wpf-migrationSkill
- avalonia-xamlSkill
- avaloniaSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 44
Use for properties that back observable collections, streams, or are performance-sensitive:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Avalonia Property System
Overview
AvaloniaProperty is the foundation of Avalonia's data binding, styling, and animations. Three kinds:
- StyledProperty — full-featured; supports styling, animation, inheritance
- DirectProperty — lightweight, CLR-field-backed; no styling/animation support
- AttachedProperty — set on foreign controls (like
Grid.Row)
StyledProperty
public static readonly StyledProperty<IBrush?> BackgroundProperty =
AvaloniaProperty.Register<MyControl, IBrush?>(
name: nameof(Background),
defaultValue: null,
inherits: false,
defaultBindingMode: BindingMode.OneWay,
validate: null,
coerce: CoerceBackground);
public IBrush? Background
{
get => GetValue(BackgroundProperty);
set => SetValue(BackgroundProperty, value);
}
private static IBrush? CoerceBackground(AvaloniaObject instance, IBrush? value)
=> value ?? Brushes.Transparent;Inherit/reuse from another class:
// Re-register an existing property as owner
public static readonly StyledProperty<IBrush?> BackgroundProperty =
Border.BackgroundProperty.AddOwner<MyPanel>();DirectProperty
Use for properties that back observable collections, streams, or are performance-sensitive:
public static readonly DirectProperty<MyControl, string> TextProperty =
AvaloniaProperty.RegisterDirect<MyControl, string>(
name: nameof(Text),
getter: o => o.Text,
setter: (o, v) => o.Text = v,
defaultBindingMode: BindingMode.TwoWay,
enableDataValidation: true);
private string _text = "";
public string Text
{
get => _text;
set => SetAndRaise(TextProperty, ref _text, value);
}SetAndRaise performs equality check, updates field, raises PropertyChanged.
AttachedProperty
public static class Grid
{
public static readonly AttachedProperty<int> RowProperty =
AvaloniaProperty.RegisterAttached<Grid, Control, int>(
name: "Row",
defaultValue: 0,
inherits: false);
public static int GetRow(Control element) => element.GetValue(RowProperty);
public static void SetRow(Control element, int value) => element.SetValue(RowProperty, value);
}XAML usage:
<TextBlock Grid.Row="1" Grid.Column="2"/>Property Value Priority (highest → lowest)
| Priority | Source |
| 1 | Animation |
| 2 | Local value (SetValue / binding at LocalValue) |
| 3 | Style trigger (active pseudoclass setter) |
| 4 | Template binding (BindingPriority.Template; 11.x name TemplatedParent was removed in 12) |
| 5 | Style setter (non-triggered) |
| 6 | Inherited value |
| 7 | Default value |
SetCurrentValue — sets without overriding bindings/styles (priority: LocalValue but clears on style change):
// Doesn't break two-way binding
myControl.SetCurrentValue(IsCheckedProperty, true);Observing Property Changes
On a specific instance (reactive):
myTextBox
.GetObservable(TextBox.TextProperty)
.Subscribe(text => Console.WriteLine($"Text: {text}"));
// With debounce (requires System.Reactive)
myTextBox
.GetObservable(TextBox.TextProperty)
.Throttle(TimeSpan.FromMilliseconds(300))
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(HandleTextChanged);In a control, override OnPropertyChanged:
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == ValueProperty)
{
var newValue = change.GetNewValue<int>();
var oldValue = change.GetOldValue<int>();
UpdateVisuals(newValue);
}
}Static class handler (fires for all instances):
static MyControl()
{
ValueProperty.Changed.AddClassHandler<MyControl>((control, e) =>
control.OnValueChanged(e));
// Or multiple properties
AffectsRender<MyControl>(ForegroundProperty, BackgroundProperty, PaddingProperty);
AffectsMeasure<MyControl>(WidthProperty, HeightProperty);
AffectsArrange<MyControl>(AlignmentProperty);
}AffectsRender / AffectsMeasure / AffectsArrange — declare layout/render dependencies efficiently.
Inherited Properties
public static readonly StyledProperty<FlowDirection> FlowDirectionProperty =
AvaloniaProperty.Register<Control, FlowDirection>(
nameof(FlowDirection),
defaultValue: FlowDirection.LeftToRight,
inherits: true);Child controls inherit the value from their nearest ancestor that sets it explicitly.
Metadata Override
Override default value or coerce function for a subclass:
static MyControl()
{
BackgroundProperty.OverrideMetadata<MyControl>(
new StyledPropertyMetadata<IBrush?>(
defaultValue: Brushes.White,
defaultBindingMode: BindingMode.OneWay,
coerce: MyCoerce));
}Data Validation
Enable on a property with enableDataValidation: true, then throw in setter or implement INotifyDataErrorInfo. (12.0+) such properties report validation errors automatically; remove UpdateDataValidation overrides that only call DataValidationErrors.SetError. To keep custom handling, override UpdateDataValidation(AvaloniaProperty, BindingValueType, Exception?) and skip the base call for that property. Data-annotations validation is opt-in in 12 (on by default in 11.x).
private int _age;
public int Age
{
get => _age;
set
{
if (value < 0 || value > 150)
throw new ArgumentOutOfRangeException(nameof(Age), "Age must be 0–150");
SetAndRaise(AgeProperty, ref _age, value);
}
}Common Mistakes
- Field must end with
Property— convention:FooPropertyfor public propertyFoo; breaks tooling otherwise DirectPropertyfor rarely-changed values — incurs no overhead, but can't be used in styles or animations; useStyledPropertyif styling needed- Forgetting
SetAndRaiseinDirectPropertysetter — plain field assignment won't notify bindings - Setting value in constructor via property setter — creates a local value that blocks style/theme overrides; use
SetCurrentValueor set field directly in constructor AddOwnervs.Register—AddOwnershares metadata and identity with source property (sameAvaloniaPropertyinstance); bindings between types sharing a property work correctly- (11.x)
IStyleable,BindingPriority.TemplatedParent— removed in 12; useStyledElementandBindingPriority.Template change.GetNewValue<T>()— must match registered type exactly; mismatched cast throwsInvalidCastException
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

