xaml-csharp-development-skill-for-avalonia

User Views, View Locator, and Tree Patterns

Table of Contents

  1. Scope and APIs
  2. View Locator Patterns
  3. Reflection-Free Locator Pattern
  4. Logical vs Visual Tree
  5. Best Practices
  6. Troubleshooting

Scope and APIs

Primary APIs:

Reference source files:

View Locator Patterns

Avalonia resolves view content via data templates. For view-model-driven composition:

Important detail from DataTemplates API:

Example usage in app resources:

<Application.DataTemplates>
  <local:ViewLocator />
</Application.DataTemplates>

Reflection-Free Locator Pattern

The sample ViewLocator uses Type.GetType and Activator.CreateInstance, which is simple but not trim/AOT friendly.

Prefer explicit registration:

using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Controls.Templates;

public sealed class ViewLocator : IDataTemplate
{
    private readonly Dictionary<Type, Func<Control>> _map = new()
    {
        [typeof(MainViewModel)] = static () => new MainView(),
        [typeof(SettingsViewModel)] = static () => new SettingsView(),
    };

    public Control? Build(object? data)
    {
        if (data is null)
            return null;

        return _map.TryGetValue(data.GetType(), out var factory)
            ? factory()
            : new TextBlock { Text = $"No view for {data.GetType().Name}" };
    }

    public bool Match(object? data) => data is ViewModelBase;
}

Why this pattern is preferred:

Logical vs Visual Tree

Use the right tree for the job.

Logical tree APIs (ILogical, LogicalExtensions):

Visual tree APIs (VisualExtensions):

Guidance:

Best Practices

Troubleshooting

  1. Data template not chosen:
    • Match returns false.
    • For typed templates in DataTemplates, missing DataType can invalidate setup.
  2. Wrong ancestor found:
    • You used visual-tree APIs when logical parent chain was needed, or vice versa.
  3. Locator fails after trimming:
    • Reflection-based locator (Type.GetType + Activator) got trimmed.
    • Replace with explicit dictionary/factory mapping.
  4. Recycled item controls showing stale state:
    • If using IRecyclingDataTemplate, ensure control state is fully rebound/reset.

XAML-First and Code-Only Usage

Default mode:

XAML-first complete example:

<Application xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="using:MyApp"
             x:Class="MyApp.App">
  <Application.DataTemplates>
    <local:ViewLocator />
  </Application.DataTemplates>
</Application>
<ContentControl xmlns="https://github.com/avaloniaui"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                Content="{Binding CurrentViewModel}" />

Code-only alternative (on request):

using Avalonia.Controls;

var host = new ContentControl
{
    DataContext = shellViewModel
};
host.Bind(ContentControl.ContentProperty, new Binding(nameof(ShellViewModel.CurrentViewModel)));

// Locator still maps VM -> View via IDataTemplate.