Primary APIs:
IDataTemplateDataTemplateDataTemplatesFuncDataTemplateITypedDataTemplateLogicalExtensionsVisualExtensionsReference source files:
src/Avalonia.Controls/Templates/IDataTemplate.cssrc/Avalonia.Controls/Templates/DataTemplates.cssrc/Avalonia.Controls/Templates/FuncDataTemplate.cssrc/Avalonia.Base/LogicalTree/LogicalExtensions.cssrc/Avalonia.Base/VisualTree/VisualExtensions.cssamples/SafeAreaDemo/ViewLocator.csAvalonia resolves view content via data templates. For view-model-driven composition:
Application.DataTemplates or local DataTemplates.Important detail from DataTemplates API:
DataTemplates collection must have DataType when typed.Example usage in app resources:
<Application.DataTemplates>
<local:ViewLocator />
</Application.DataTemplates>
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:
Activator reflection path.Use the right tree for the job.
Logical tree APIs (ILogical, LogicalExtensions):
GetLogicalAncestors()FindLogicalAncestorOfType<T>()GetLogicalDescendants()Visual tree APIs (VisualExtensions):
GetVisualAncestors()FindAncestorOfType<T>()FindDescendantOfType<T>()GetVisualAt(point)Guidance:
39-visual-tree-inspection-and-traversal.md.40-logical-tree-inspection-and-traversal.md.switch in UI containers.DataType whenever possible.Match returns false.DataTemplates, missing DataType can invalidate setup.Type.GetType + Activator) got trimmed.IRecyclingDataTemplate, ensure control state is fully rebound/reset.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.