我正在try 将我的应用程序设置为根据设备的名称显示不同的视图.不幸的是,我似乎无法加载View,尽管正在调用ViewModel.我不完全确定我错过了什么.

目前,当应用程序加载时,唯一显示的是主窗口,但没有在其中加载视图.

如何加载视图?

这是我的MainWindow.axaml:

<Window
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:TAStagingApp.ViewModels.Implementations;assembly=TAStagingApp.ViewModels"
    mc:Ignorable="d"
    d:DesignWidth="800"
    d:DesignHeight="450"
    x:Class="TAStagingApp.Views.MainWindow"
    x:DataType="vm:MainWindowViewModel"
    Background="{StaticResource TABackgroundColor}"
    Icon="/Assets/tastaging.png"
    WindowStartupLocation="CenterScreen"
    Title="TA Staging">

    <Design.DataContext>
        <vm:MainWindowViewModel />
    </Design.DataContext>
    <Grid>
        <ContentPresenter Name="StagingContent"/>
    </Grid>

</Window>

和MainWindow.axaml.cs

namespace TAStagingApp.Views;
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }

    public void SetContent(Control control)
    {
        var mainContent = this.FindControl<ContentPresenter>("StagingContent");
        mainContent!.Content = control;
    }
}

App.axaml.cs

using AvaloniaApplication = Avalonia.Application;

namespace TAStagingApp;
public partial class App : AvaloniaApplication
{
    public override void Initialize()
    {
        AvaloniaXamlLoader.Load(this);
    }

    public override void OnFrameworkInitializationCompleted()
    {
        var viewModelLoader = new ViewModelLoader(new MainWindow());
        ServiceLocator.Initialize(viewModelLoader);

        if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
        {
            DataContext = GetRequiredService<IMainWindowViewModel>();
            desktop.MainWindow = new MainWindow
            {
                DataContext = DataContext,
            };

            viewModelLoader.LoadContentViewBasedOnComputerName();
        }

        base.OnFrameworkInitializationCompleted();
    }

    private static T GetRequiredService<T>() => Locator.Current.GetRequiredService<T>();
}

ViewModelLoader.cs

namespace TAStagingApp.DependencyInjection.Loaders;
public sealed class ViewModelLoader(MainWindow mainWindow) : IViewModelLoader
{
    private readonly MainWindow _mainWindow = mainWindow;

    public void LoadContentViewBasedOnComputerName()
    {
        var serviceProvider = DeviceTypeHelper.GetDeviceTypeServiceProvider();
        var deviceType = DeviceTypeHelper.GetDeviceType(serviceProvider);

        Control contentView = deviceType.Value.ToString() switch
        {
            var device when device.Equals(DeviceType.Server.ToString()) => new ServerConfigureView(),
            var device when device.Equals(DeviceType.Terminal.ToString()) => new TerminalConfigureView(),
            var device when device.Equals(DeviceType.Kitchen.ToString()) => new TerminalConfigureView(),
            _ => new AdminView()
        };

        _mainWindow.SetContent(contentView);
    }
}

MainWindowViewModel.cs

namespace TAStagingApp.ViewModels.Implementations;

public class MainWindowViewModel : ViewModelBase, IMainWindowViewModel
{
    public MainWindowViewModel(IActivateViewModel viewModel)
    {
        if (viewModel.GetType() == typeof(TerminalConfigureViewModel))
        {
            TerminalConfigureViewModel = viewModel;
        }
        else if (viewModel.GetType() == typeof(ServerConfigureViewModel))
        {
            ServerConfigureViewModel = viewModel;
        }
        else
        {
            AdminViewModel = viewModel;
        }

        Activate(viewModel);
    }

    public MainWindowViewModel()
    {
    }

    public IActivateViewModel AdminViewModel { get; } = default!;

    public IActivateViewModel TerminalConfigureViewModel { get; } = default!;

    public IActivateViewModel ServerConfigureViewModel { get; } = default!;

    private static void Activate(IActivateViewModel viewModel)
        => viewModel.Activate();
}

我已经看了这两天了,我不知道我错过了什么.

谢谢

推荐答案

问题是您的ViewModelLoader使用的是MainWindow的实例,该实例与实际的

public override void OnFrameworkInitializationCompleted()
{
    var viewModelLoader = new ViewModelLoader(new MainWindow()); // <<<< this window 
    ServiceLocator.Initialize(viewModelLoader);

    if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
    {
        DataContext = GetRequiredService<IMainWindowViewModel>();
        desktop.MainWindow = new MainWindow // <<< diffrent from this window
        {
            DataContext = DataContext,
        };

        viewModelLoader.LoadContentViewBasedOnComputerName();
    }

    base.OnFrameworkInitializationCompleted();
}

您可以通过使用应用程序主窗口实例化ViewModelLoader来修复它

public override void OnFrameworkInitializationCompleted()
{
    if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
    {
        DataContext = GetRequiredService<IMainWindowViewModel>();
        desktop.MainWindow = new MainWindow
        {
            DataContext = DataContext,
        };

        // <<< instantiate ViewModelLoader with the application MainWindow
        var viewModelLoader = new ViewModelLoader(desktop.MainWindow);
        ServiceLocator.Initialize(viewModelLoader);

        viewModelLoader.LoadContentViewBasedOnComputerName();
    }

    base.OnFrameworkInitializationCompleted();
}

附带建议

事实上,你应该重新设计你的架构,因为你的架构看起来死气沉沉的!

如果我穿上你,我会用data templates让我的生活变得轻松!

 <Window.DataTemplates>
   <DataTemplate DataType="{x:Type vm:ServerConfigureViewModel}">
     <view:ServerConfigureView/>      
   </DataTemplate>

   <DataTemplate DataType="{x:Type vm:TerminalConfigureViewModel}">
     <view:TerminalConfigureView/>
   </DataTemplate>

   <DataTemplate DataType="{x:Type vm:AdminViewModel}">
     <view:AdminView/>
   </DataTemplate>
 </Window.DataTemplates>

然后放入你的名为CurrentViewModelActivatedViewModel或其他类型ViewModelBaseMainViewModle财产

public class MainWindowViewModel : ViewModelBase
{
    private ViewModelBase _currentViewModel;

    public ViewModelBase CurrentViewModdel
    {
        get => _currentViewModel;
        set => SetProperty(ref _currentViewModel, value);
    }

}

所有的ServerConfigureViewModelTerminalConfigureViewModelAdminViewModel都应该继承自ViewModelBase,并且可以签名到CurrentViewModdel

并在主窗口中绑定到它

<Grid>
  <ContentControl Content="{Binding CurrentViewModel}"/>
</Grid>

现在,如果您在主窗口中更改CurrentViewModdel,则视图将在没有ViewModleLocator和此人员的所有代码的情况下更改

Csharp相关问答推荐

在Microsoft XNA框架(MonoGame)中旋转相机

为什么.Equals(SS,StringComparison. ClientCultureIgnoreCase)在Net 4.8和6.0之间不同?

PredicateBuilder不是循环工作,而是手动工作

使用C#中的SDK在Microsoft Graph API上使用SubscribedSkus的问题

.NET 8 Web-API返回空列表

如何在C#中使用正则表达式抓取用逗号分隔的两个单词?

将轮询与超时同步

在命名管道上使用GRPC ASP.NET核心时如何配置命名管道权限

在静态模式下实例化配置

如何使用自定义负载均衡器管理Ocelot负载均衡器中的多线程和批读取

如何让NLog停止写入冗余信息?

.NET8Blazor-为什么Rapzor渲染在for循环之后显示?

毛伊岛.NET 8图片不再适合按钮

为什么Swashbakle/Swagger在参数中包含变量名?

ASP.NET Core 8 Web API:如何添加版本控制?

在.Net 8 Visual Studio 2022中启用本机AOT发布时发布失败

如何在更新数据库实体时忽略特定字段?

为什么C#中的类型别名不能在另一个别名中使用?

外部应用&&的LINQ;左外部连接&类似于PostgreSQL的查询

在C#中删除多个不同名称的会话