OutWit.Common.MVVM.Avalonia 2.0.4

dotnet add package OutWit.Common.MVVM.Avalonia --version 2.0.4
                    
NuGet\Install-Package OutWit.Common.MVVM.Avalonia -Version 2.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="OutWit.Common.MVVM.Avalonia" Version="2.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="OutWit.Common.MVVM.Avalonia" Version="2.0.4" />
                    
Directory.Packages.props
<PackageReference Include="OutWit.Common.MVVM.Avalonia" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add OutWit.Common.MVVM.Avalonia --version 2.0.4
                    
#r "nuget: OutWit.Common.MVVM.Avalonia, 2.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package OutWit.Common.MVVM.Avalonia@2.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=OutWit.Common.MVVM.Avalonia&version=2.0.4
                    
Install as a Cake Addin
#tool nuget:?package=OutWit.Common.MVVM.Avalonia&version=2.0.4
                    
Install as a Cake Tool

OutWit.Common.MVVM.Avalonia

Avalonia-specific MVVM components and utilities, including source generator for automatic StyledProperty, DirectProperty, and AttachedProperty generation.

Features

  • Source Generator for Properties: Automatically generate StyledProperty, DirectProperty, and AttachedProperty from attributes
  • AvaloniaDispatcher: IDispatcher implementation for UI thread invocation
  • Binding Utilities: Helper methods for property registration
  • Visual Tree Traversal: Extension methods for navigating Avalonia visual tree
  • BindingProxy: Binding proxy for DataContext access
  • DataTemplate Utilities: Helper methods for DataTemplate creation

Installation

dotnet add package OutWit.Common.MVVM.Avalonia

This automatically includes:

  • OutWit.Common.MVVM (base cross-platform package)
  • OutWit.Common.MVVM.Avalonia.Generator (source generator)
  • OutWit.Common.Logging

Quick Start

Source Generator for StyledProperty

The simplest way to create StyledProperties:

using Avalonia.Controls;
using OutWit.Common.MVVM.Avalonia.Attributes;

namespace MyApp.Controls
{
    public partial class CustomButton : Button
    {
        [StyledProperty(DefaultValue = "Click Me")]
        public string Label { get; set; }

        [StyledProperty(BindsTwoWayByDefault = true)]
        public bool IsPressed { get; set; }
    }
}

Important: Mark your class as partial to allow source generator to add code.

The generator automatically creates:

// Generated code (you don't write this):
public static readonly StyledProperty<string> LabelProperty = 
    AvaloniaProperty.Register<CustomButton, string>(nameof(Label), "Click Me");
public static readonly StyledProperty<bool> IsPressedProperty = 
    AvaloniaProperty.Register<CustomButton, bool>(nameof(IsPressed), defaultBindingMode: BindingMode.TwoWay);

DirectProperty for Performance

Use DirectProperty for frequently changing values (better performance, no style system participation):

public partial class CounterControl : Control
{
    [DirectProperty(DefaultValue = 0)]
    public int Counter { get; set; }

    [DirectProperty(BindsTwoWayByDefault = true)]
    public string Text { get; set; }
}

Generated code:

// Backing field is generated automatically
private int m_counter = 0;
public static readonly DirectProperty<CounterControl, int> CounterProperty = 
    AvaloniaProperty.RegisterDirect<CounterControl, int>(
        nameof(Counter), 
        o => o.m_counter, 
        (o, v) => o.m_counter = v,
        unsetValue: 0);

Attached Properties

using OutWit.Common.MVVM.Avalonia.Attributes;

public static partial class MyAttachedProperties
{
    [AttachedProperty(DefaultValue = false)]
    public static bool IsHighlighted { get; set; }

    [AttachedProperty(DefaultValue = 1.0, Inherits = true)]
    public static double Opacity { get; set; }
}

// Usage in AXAML:
// <Button local:MyAttachedProperties.IsHighlighted="True" />

Generated code includes Get/Set methods:

public static bool GetIsHighlighted(AvaloniaObject obj) => obj.GetValue(IsHighlightedProperty);
public static void SetIsHighlighted(AvaloniaObject obj, bool value) => obj.SetValue(IsHighlightedProperty, value);

Convention-Based Callbacks

The generator automatically discovers callback methods by naming convention:

public partial class SmartControl : Control
{
    // No need to specify OnChanged - automatically discovered!
    [StyledProperty(DefaultValue = "Hello")]
    public string Title { get; set; }

    // Convention: On{PropertyName}Changed
    private void OnTitleChanged(AvaloniaPropertyChangedEventArgs<string> e)
    {
        // Handle title change
    }

    // Convention: {PropertyName}Coerce
    private string TitleCoerce(AvaloniaObject sender, string value)
    {
        return value?.Trim() ?? "";
    }
}

Visual Tree Traversal

using OutWit.Common.MVVM.Avalonia.Utils;

// Find first child of specific type
var button = myPanel.FindFirstChildOf<Button>();

// Find all children
var allButtons = myPanel.FindAllChildrenOf<Button>();

// Find parent
var window = myButton.FindFirstParentOf<Window>();

BindingProxy for DataContext Access

<UserControl.Resources>
    <local:BindingProxy x:Key="Proxy" Data="{Binding}" />
</UserControl.Resources>

<DataGrid Items="{Binding Items}">
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataTemplate>
                <Button Command="{Binding Data.DeleteCommand, Source={StaticResource Proxy}}"
                        CommandParameter="{Binding}" />
            </DataTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

AvaloniaDispatcher

using OutWit.Common.MVVM.Avalonia.Abstractions;

// Get dispatcher for current thread
var dispatcher = AvaloniaDispatcher.UIThread;

// Invoke on UI thread
dispatcher.Invoke(() => UpdateUI());

// Async invoke
await dispatcher.InvokeAsync(() => UpdateUI());

Property Types Comparison

Type Use Case Style System Performance
StyledProperty Most properties Yes Normal
DirectProperty Frequently changing values No Better
AttachedProperty Properties on other objects Yes Normal

StyledProperty Options

Option Type Description
PropertyName string Override property name (default: {Name}Property)
DefaultValue object Default value
BindsTwoWayByDefault bool Enable two-way binding by default
Inherits bool Value inherited by child elements
OnChanged string Property changed callback method name
Coerce string Coerce value callback method name

DirectProperty Options

Option Type Description
PropertyName string Override property name
DefaultValue object Default value (also used as unset value)
BindsTwoWayByDefault bool Enable two-way binding by default
OnChanged string Property changed callback method name

AttachedProperty Options

Option Type Description
PropertyName string Override property name
DefaultValue object Default value
Inherits bool Value inherited by child elements
OnChanged string Property changed callback method name
Coerce string Coerce value callback method name
  • OutWit.Common.MVVM - Cross-platform base classes
  • OutWit.Common.MVVM.WPF - WPF-specific implementation
  • OutWit.Common.MVVM.Blazor - Blazor-specific implementation

License

Licensed under the Apache License, Version 2.0. See LICENSE.

Attribution (optional)

If you use OutWit.Common.MVVM.Avalonia in a product, a mention is appreciated (but not required), for example: "Powered by OutWit.Common.MVVM.Avalonia (https://ratner.io/)".

Trademark / Project name

"OutWit" and the OutWit logo are used to identify the official project by Dmitry Ratner.

You may:

  • refer to the project name in a factual way (e.g., "built with OutWit.Common.MVVM.Avalonia");
  • use the name to indicate compatibility (e.g., "OutWit.Common.MVVM.Avalonia-compatible").

You may not:

  • use "OutWit.Common.MVVM.Avalonia" as the name of a fork or a derived product in a way that implies it is the official project;
  • use the OutWit.Common.MVVM.Avalonia logo to promote forks or derived products without permission.
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.4 133 1/25/2026
2.0.3 103 1/8/2026
2.0.2 111 1/2/2026
2.0.1 99 1/2/2026
2.0.0 102 1/2/2026