Default to precompiled XAML + compiled bindings. Treat reflection-based or runtime-loaded paths as explicit exceptions.
InitializeComponent().AvaloniaXamlLoader.Load(this) is expected through generated initialization wiring.AvaloniaXamlLoader.Load(Uri, ...) and runtime loaders (AvaloniaRuntimeXamlLoader) are dynamic paths.RequiresUnreferencedCode and are not default-safe for trim/AOT workflows.Use runtime loaders only when the feature explicitly requires dynamic XAML (plugin/theme editor-like scenarios).
For detailed converter guidance (single-value/multi-value, XAML resources, function-based converters, and binding wiring), see:
For advanced typed/untyped binding value semantics (BindingValue<T>, BindingNotification, InstancedBinding, IndexerDescriptor), see:
For RelativeSource, StaticResource, and name-scope resolution markup (ResolveByNameExtension), see:
Advanced binding-assignment contract:
AssignBindingAttribute marks members where a binding object should be assigned instead of initiating a live binding.Primary APIs:
{CompiledBinding ...} with x:DataTypeCompiledBinding, CompiledBindingPath, CompiledBindingPathBuilderBenefits:
Primary APIs:
{Binding ...} from Avalonia.Markup.Data.Binding (inherits reflection binding behavior){ReflectionBinding ...} explicit extensionReflectionBindingTradeoffs:
x:DataType on root views and templates.{CompiledBinding ...} where practical.Example:
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:MyApp.ViewModels"
x:Class="MyApp.Views.MainView"
x:DataType="vm:MainViewModel">
<StackPanel Spacing="8">
<TextBox Text="{CompiledBinding Query, Mode=TwoWay}" />
<Button Content="Search" Command="{CompiledBinding SearchCommand}" />
<TextBlock Text="{CompiledBinding StatusText}" />
</StackPanel>
</UserControl>
Path capabilities (through grammar/builders):
^ operator in XAML path syntax).Example stream binding in XAML:
<TextBlock Text="{CompiledBinding ClockObservable^, Mode=OneWay}" />
BindingBasetextBlock.Bind(TextBlock.TextProperty,
new CompiledBinding(new CompiledBindingPathBuilder()
.Property(/* generated property info */)
.Build()));
IDisposable sub = textBlock.Bind(
TextBlock.TextProperty,
viewModel.StatusStream);
textBlock.Bind(TextBlock.TextProperty, viewModel.StatusStream.ToBinding());
DataTemplate and DataTypeDataTemplates collections require typed templates in shared/global contexts.
Use:
DataTemplate x:DataType="..."TreeDataTemplate x:DataType="..."FuncDataTemplate for C# template construction when needed.x:NameGenerator options (from Avalonia.Generators.props):
AvaloniaNameGeneratorBehaviorAvaloniaNameGeneratorDefaultFieldModifierAvaloniaNameGeneratorFilterByPathAvaloniaNameGeneratorFilterByNamespaceUse:
FallbackValue, TargetNullValue, StringFormat).When debugging or building advanced binding flows, use these APIs deliberately:
BindingValue<T> + BindingValueType,BindingNotification + BindingErrorType,BindingValue<T>.FromUntyped(...), ToUntyped(), ToOptional(),BindingOperations.GetBindingExpressionBase(...).State mapping you should rely on:
BindingValue<T>.Unset maps to AvaloniaProperty.UnsetValue,BindingValue<T>.DoNothing maps to BindingOperations.DoNothing,BindingError / DataValidationError can carry fallback values,BindingNotification can carry both error metadata and a fallback/passthrough value.Example: inspect typed binding stream safely.
using Avalonia;
using Avalonia.Data;
IDisposable sub = textBox
.GetBindingObservable(TextBox.TextProperty)
.Subscribe(v =>
{
switch (v.Type)
{
case BindingValueType.Value:
viewModel.LastValidText = v.GetValueOrDefault() ?? string.Empty;
break;
case BindingValueType.DataValidationError:
case BindingValueType.BindingError:
viewModel.LastBindingError = v.Error?.Message;
break;
case BindingValueType.UnsetValue:
// Target will fall back to the property's unbound/default behavior.
break;
case BindingValueType.DoNothing:
// Preserve current target state.
break;
}
});
Example: explicit source update for UpdateSourceTrigger=Explicit.
var expr = BindingOperations.GetBindingExpressionBase(textBox, TextBox.TextProperty);
expr?.UpdateSource();
Advanced app code occasionally needs:
InstancedBinding factory helpers (OneWay, TwoWay, OneTime, OneWayToSource),IndexerDescriptor (!property / ~property operator paths) for concise property-indexer binding wiring.Compatibility note:
IBinding.Initiate(...) and BindingOperations.Apply(...) are obsolete compatibility paths in Avalonia 11.3.12 and are not recommended for new app code.These APIs are useful for dynamic binding infrastructure and diagnostics tooling, not as default app authoring style. Prefer normal XAML binding syntax unless you need dynamic composition.
{Binding ...} without x:DataType in large apps.Default mode:
XAML-first complete example:
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:MyApp.ViewModels"
x:Class="MyApp.Views.SearchView"
x:DataType="vm:SearchViewModel">
<StackPanel Margin="16" Spacing="8">
<TextBox Watermark="Query"
Text="{CompiledBinding Query, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Button Content="Search" Command="{CompiledBinding SearchCommand}" />
<TextBlock Text="{CompiledBinding StatusText}" />
</StackPanel>
</UserControl>
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace MyApp.Views;
public partial class SearchView : UserControl
{
public SearchView() => InitializeComponent();
private void InitializeComponent() => AvaloniaXamlLoader.Load(this);
}
Code-only alternative (on request):
using Avalonia;
using Avalonia.Controls;
using Avalonia.Data;
var panel = new StackPanel { Margin = new Thickness(16), Spacing = 8 };
var input = new TextBox { Watermark = "Query" };
input.Bind(TextBox.TextProperty, new Binding(nameof(SearchViewModel.Query))
{
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
var run = new Button { Content = "Search" };
run.Bind(Button.CommandProperty, new Binding(nameof(SearchViewModel.SearchCommand)));
var status = new TextBlock();
status.Bind(TextBlock.TextProperty, new Binding(nameof(SearchViewModel.StatusText)));
panel.Children.Add(input);
panel.Children.Add(run);
panel.Children.Add(status);