xaml-csharp-development-skill-for-avalonia

Value Converters

Table of Contents

  1. Scope and APIs
  2. Converter Shapes at a Glance
  3. Class-Based IValueConverter in XAML Resources
  4. Function-Based Single-Value Converters (FuncValueConverter)
  5. Built-in Converter Helpers (BoolConverters, StringConverters, ObjectConverters)
  6. Multi-Value Conversion with MultiBinding and IMultiValueConverter
  7. Function-Based Multi-Value Converters (FuncMultiValueConverter)
  8. Wiring Converters into Reflection/Compiled/Template Bindings
  9. Return Semantics and Error Handling
  10. Best Practices
  11. Troubleshooting

Scope and APIs

Primary APIs:

Built-in converter helpers:

Reference source files:

Converter Shapes at a Glance

Single-value conversion:

Multi-value conversion:

Authoring styles:

Class-Based IValueConverter in XAML Resources

Converter class:

using System;
using System.Globalization;
using Avalonia;
using Avalonia.Data.Converters;

public sealed class StatusToTextConverter : IValueConverter
{
    public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
        => value switch
        {
            true => "Online",
            false => "Offline",
            _ => AvaloniaProperty.UnsetValue
        };

    public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
        => value switch
        {
            "Online" => true,
            "Offline" => false,
            _ => AvaloniaProperty.UnsetValue
        };
}

Register and use in XAML resources:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:conv="using:MyApp.Converters">
  <Window.Resources>
    <conv:StatusToTextConverter x:Key="StatusToText" />
  </Window.Resources>

  <TextBlock Text="{Binding IsOnline, Converter={StaticResource StatusToText}}" />
</Window>

Resource scope can be:

Function-Based Single-Value Converters (FuncValueConverter)

C# wiring example:

using Avalonia.Data;
using Avalonia.Data.Converters;

var textConverter = new FuncValueConverter<decimal, string>(v => v.ToString("0.00"));

textBlock.Bind(TextBlock.TextProperty, new ReflectionBinding(nameof(ViewModel.Total))
{
    Converter = textConverter
});

With converter parameter:

var suffixConverter = new FuncValueConverter<string, string, string>((value, suffix) =>
    $"{value}{suffix}");

textBlock.Bind(TextBlock.TextProperty, new ReflectionBinding(nameof(ViewModel.Name))
{
    Converter = suffixConverter,
    ConverterParameter = " (active)"
});

Tip:

Built-in Converter Helpers (BoolConverters, StringConverters, ObjectConverters)

Avalonia ships reusable static converters.

XAML usage with x:Static:

<TextBlock IsVisible="{Binding Item, Converter={x:Static ObjectConverters.IsNotNull}}" />
<ToggleButton IsChecked="{Binding IsEnabled, Converter={x:Static BoolConverters.Not}}" />
<TextBlock IsVisible="{Binding Query, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />

Useful built-ins:

Built-in multi-converter with MultiBinding:

<TextBlock.IsVisible>
  <MultiBinding Converter="{x:Static BoolConverters.And}">
    <Binding Path="IsEnabled" />
    <Binding Path="HasSelection" />
  </MultiBinding>
</TextBlock.IsVisible>

Multi-Value Conversion with MultiBinding and IMultiValueConverter

IMultiValueConverter:

Class-based multi converter:

using System;
using System.Collections.Generic;
using System.Globalization;
using Avalonia;
using Avalonia.Data.Converters;

public sealed class FullNameConverter : IMultiValueConverter
{
    public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
    {
        var first = values.Count > 0 ? values[0]?.ToString() : null;
        var last = values.Count > 1 ? values[1]?.ToString() : null;

        if (string.IsNullOrWhiteSpace(first) && string.IsNullOrWhiteSpace(last))
            return AvaloniaProperty.UnsetValue;

        return $"{first} {last}".Trim();
    }
}

XAML wiring:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:conv="using:MyApp.Converters">
  <Window.Resources>
    <conv:FullNameConverter x:Key="FullNameConverter" />
  </Window.Resources>

  <TextBlock>
    <TextBlock.Text>
      <MultiBinding Converter="{StaticResource FullNameConverter}" FallbackValue="(unknown)">
        <Binding Path="FirstName" />
        <Binding Path="LastName" />
      </MultiBinding>
    </TextBlock.Text>
  </TextBlock>
</Window>

Notes:

Function-Based Multi-Value Converters (FuncMultiValueConverter)

C# example:

using Avalonia.Data;
using Avalonia.Data.Converters;

var join = new FuncMultiValueConverter<string, string>(values => string.Join(" / ", values));

var binding = new MultiBinding
{
    Converter = join,
    Bindings =
    {
        new ReflectionBinding(nameof(ViewModel.LeftText)),
        new ReflectionBinding(nameof(ViewModel.RightText)),
    }
};

textBlock.Bind(TextBlock.TextProperty, binding);

For XAML reuse, expose converter instances via static properties and reference them with x:Static.

Wiring Converters into Reflection/Compiled/Template Bindings

Reflection binding (XAML):

<TextBlock Text="{Binding Name, Converter={StaticResource NameConverter}}" />

Compiled binding (XAML):

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="using:MyApp"
             x:DataType="local:MyVm"
             x:CompileBindings="True">
  <TextBlock Text="{CompiledBinding Name, Converter={StaticResource NameConverter}, ConverterParameter=VIP}" />
</UserControl>

Compiled binding (C# API):

var binding = CompiledBinding.Create<MyVm, decimal>(
    vm => vm.Total,
    converter: new FuncValueConverter<decimal, string>(v => v.ToString("C2")));

textBlock.Bind(TextBlock.TextProperty, binding);

Template binding:

<Border Background="{TemplateBinding Background, Converter={StaticResource BrushConverter}}" />

MultiBinding + compile bindings:

Return Semantics and Error Handling

IValueConverter guidance:

IMultiValueConverter guidance:

Best Practices

Troubleshooting

  1. Converter not found in XAML
    • Resource key missing or wrong scope.
    • Incorrect XML namespace for converter class.
  2. Converter called but value not updated
    • Converter returns BindingOperations.DoNothing.
    • UnsetValue hits fallback path unexpectedly.
  3. MultiBinding never produces output
    • One or more child bindings never initialize.
    • Converter rejects value types and returns UnsetValue.
  4. Compiled-binding view still behaves like reflection binding
    • Missing x:CompileBindings="True" and/or x:DataType.
  5. Two-way conversion fails
    • ConvertBack is missing/invalid for single-value converters.
    • MultiBinding does not provide ConvertBack semantics.