You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Avalonia UI+C#导航异常:仅显示视图路径字符串而非切换视图

问题

基于Avalonia UI的C#测试项目开发基础菜单导航系统时,导航无法正确切换视图,仅显示ViewModel的类型字符串,而非实际视图内容。相关代码如下:

MainWindowViewModel.cs

using AvaloniaApplication.ViewModels;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.ObjectModel;

namespace AvaloniaApplication.ViewModels;

public partial class MainWindowViewModel : ViewModelBase
{
#pragma warning disable CA1822 // Mark members as static

    [ObservableProperty]
    private ViewModelBase _currentPage = new HomePageViewModel();

    [ObservableProperty]
    private ListItemTemplate? _selectedListItem;

    partial void OnSelectedListItemChanged(ListItemTemplate? value)
    {
        if (value is null) return;
        var instance = Activator.CreateInstance(value.ModelType);
        if (instance is null) return;
        CurrentPage = (ViewModelBase)instance;
    }
    public ObservableCollection<ListItemTemplate> Items { get; } = new()
    {
        new ListItemTemplate(typeof(HomePageViewModel)),
        new ListItemTemplate(typeof(RosterViewModel))
    };

}

public class ListItemTemplate
{
public ListItemTemplate(Type type)
{
    ModelType = type;
    Label = type.Name.Replace("PageViewModel", "");
}

public string Label { get; }
public Type ModelType { get; }
}

MainWindow.axaml

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:AvaloniaApplication.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="AvaloniaApplication.Views.MainWindow"
        x:DataType="vm:MainWindowViewModel"
        Icon="/Assets/avalonia-logo.ico"
        Title="AvaloniaApplication">

    <Design.DataContext>
        <!-- This only sets the DataContext for the previewer in an IDE,
             to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
        <vm:MainWindowViewModel/>
    </Design.DataContext>

  <SplitView IsPaneOpen="True"
             OpenPaneLength="100"
             Background="White"
             PaneBackground="Purple">
    <SplitView.Pane>

      <ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedListItem}">
        <ListBox.ItemTemplate>
          <DataTemplate DataType="{x:Type vm:ListItemTemplate}">
            <StackPanel>
              <TextBlock Text="{Binding Label}"/>
            </StackPanel>
          </DataTemplate>
        </ListBox.ItemTemplate>
      </ListBox>
   

    </SplitView.Pane>

    <SplitView.Content>
      <TransitioningContentControl Content="{Binding CurrentPage}"/>
      
    </SplitView.Content>
  </SplitView>

</Window>
解决方案

问题核心是**TransitioningContentControl绑定了ViewModel,但Avalonia没有找到对应的View来渲染它**,因此默认输出ViewModel的ToString()结果(即类型字符串)。修复需建立ViewModel与View的关联:

1. 确保存在对应View

确认每个ViewModel都有匹配的View文件:

  • HomePageViewModel → HomePage.axaml(位于AvaloniaApplication.Views命名空间)
  • RosterViewModel → RosterPage.axaml(位于AvaloniaApplication.Views命名空间)

2. 手动注册DataTemplate关联

在MainWindow.axaml中添加View命名空间引用,并为每个ViewModel配置DataTemplate:

步骤1:添加命名空间

在Window标签中加入Views命名空间:

xmlns:views="clr-namespace:AvaloniaApplication.Views"

步骤2:添加资源级DataTemplate

在Window内添加资源块,指定ViewModel对应的View:

<Window.Resources>
    <DataTemplate DataType="{x:Type vm:HomePageViewModel}">
        <views:HomePage />
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:RosterViewModel}">
        <views:RosterPage />
    </DataTemplate>
</Window.Resources>

3. 验证ViewModel实例创建逻辑

确保HomePageViewModel和RosterViewModel都有无参构造函数,否则Activator.CreateInstance会创建失败,导致CurrentPage无法更新。

4. 可选:全局自动匹配(ViewLocator)

如果遵循命名约定(如XXXViewModel对应XXXView/XXXPage),可以实现ViewLocator自动关联,无需手动配置每个DataTemplate:

实现ViewLocator类

using Avalonia.Controls;
using Avalonia.Controls.Templates;
using AvaloniaApplication.ViewModels;

namespace AvaloniaApplication;

public class ViewLocator : IDataTemplate
{
    public IControl Build(object data)
    {
        var viewModelType = data.GetType();
        // 替换ViewModel后缀为Page,匹配你的命名规则
        var viewTypeName = viewModelType.FullName!.Replace("ViewModel", "Page");
        var viewType = Type.GetType(viewTypeName);

        if (viewType != null)
        {
            return (Control)Activator.CreateInstance(viewType)!;
        }

        return new TextBlock { Text = $"未找到对应视图: {viewTypeName}" };
    }

    public bool Match(object data)
    {
        return data is ViewModelBase;
    }
}

在App.axaml中注册

<Application xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:AvaloniaApplication"
             x:Class="AvaloniaApplication.App">
    <Application.DataTemplates>
        <local:ViewLocator />
    </Application.DataTemplates>
</Application>

完成上述操作后,TransitioningContentControl会根据绑定的CurrentPage自动渲染对应的View,实现正常的视图切换。

内容的提问来源于stack exchange,提问作者Kevin Morgan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 16:55:29