Avalonia中使用Prism实现区域导航功能

前言

上一篇文章我们讲了在Avalonia开发中,引入Prism框架来完成项目的MVVM迁移。本章内容将带领大家学习如何在Avalonia中使用Prism框架实现区域导航功能。如果你还不知道Avalonia中如何引入Prism框架,请看我上一篇文章:Avalonia框架下面使用Prism框架实现MVVM模式

新建导航页

我们首先在相应的文件夹下面创建ViewA、ViewB以及他们所对应的ViewModel,创建好的目录结构如下:
Avalonia中使用Prism实现区域导航功能_第1张图片
创建View和WPF里面差不多,但是Avalonia需要手动的指定绑定的VM的DataType类型。其实通过后面的验证,其实指定不指定其实在Prism框架下面没有影响,项目依然能够正常运行。但是有一个问题就是如果你设置了DataType类型,你在后期界面绑定数据的时候会有智能提示出来方便开发。
Avalonia中使用Prism实现区域导航功能_第2张图片
这里有个小细节需要 特别注意,这里面有个小bug,我们创建的ViewModel或者新引入nuget动态库文件以后,如果我们想在view里面进行引用,应该先全局生成一下解决方案,这样在编码的时候才能出现智能提示,希望官方后期能够修复这个bug.

创建ViewModel

创建ViewModel,这里面其实和WPF里面是一样的,这里就不在赘述,代码如下:

using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AvaloniaTest.ViewModels
{
    public class ViewAViewModel : ViewModelBase, INavigationAware
    {
        private string _title="ViewA";

        public string Title
        {
            get => _title; 
            set
            {
                SetProperty(ref _title, value);
            }
        }

        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            
        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            
        }
    }
}

容器里面注册导航资源

我们在App.xaml里面注册导航用到的ViewA和ViewB,代码如下:

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.Register<MainView>();
        containerRegistry.RegisterForNavigation<ViewA,ViewAViewModel>(nameof(ViewA));
        containerRegistry.RegisterForNavigation<ViewB,ViewBViewModel>(nameof(ViewB));
    }

Avalonia中使用Prism实现区域导航功能_第3张图片

创建显示区域

在MainView里面创建显示区域,其实和WPF里面是一模一样的。
Avalonia中使用Prism实现区域导航功能_第4张图片

ViewModel里面的导航实现

这里面主要通过构造函数传过来一个IRegionManager参数,然后通过这个区域管理对象对我们的区域实现导航功能,其实实现也都和WPF里面一样。
Avalonia中使用Prism实现区域导航功能_第5张图片

完整的代码实现

MainView.axaml

<UserControl 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:AvaloniaTest.ViewModels"
             xmlns:prism="http://prismlibrary.com/"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="AvaloniaTest.Views.MainView"
             prism:ViewModelLocator.AutoWireViewModel="True"
             x:DataType="vm:MainViewModel">
  <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) -->
  </Design.DataContext>

  <Grid RowDefinitions="50,*">
    <Grid ColumnDefinitions="*,*,*">
      <TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
      <Button Content="ViewA" Grid.Column="1" Command="{Binding ViewACommand}"></Button>
      <Button Content="ViewB" Grid.Column="2" Command="{Binding ViewBCommand}"></Button>
    </Grid>
    <ContentControl Grid.Row="1" prism:RegionManager.RegionName="mainContent"></ContentControl>
  </Grid>

</UserControl>

MainViewModel.cs

using AvaloniaTest.Views;
using Prism.Commands;
using Prism.Regions;

namespace AvaloniaTest.ViewModels;

public class MainViewModel : ViewModelBase
{

    private readonly IRegionManager _regionManager;
    public MainViewModel(IRegionManager regionManager) {
        _regionManager = regionManager;
        _regionManager.RegisterViewWithRegion("mainContent", nameof(ViewB));

        ViewACommand = new DelegateCommand(() => {
            _regionManager.RequestNavigate("mainContent", nameof(ViewA));
        });

        ViewBCommand = new DelegateCommand(() => {
            _regionManager.RequestNavigate("mainContent", nameof(ViewB));
        });
    }

    public DelegateCommand ViewACommand { get; set; }
    public DelegateCommand ViewBCommand { get; set; }

    public string Greeting => "Welcome to Avalonia!";

}

ViewA.axaml

<UserControl 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="using:AvaloniaTest.ViewModels"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:DataType="vm:ViewAViewModel"
             x:Class="AvaloniaTest.Views.ViewA" Background="Red">
  <TextBlock Text="{Binding Title}"></TextBlock>
</UserControl>

ViewAViewModel.cs

using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AvaloniaTest.ViewModels
{
    public class ViewAViewModel : ViewModelBase, INavigationAware
    {
        private string _title="ViewA";

        public string Title
        {
            get => _title; 
            set
            {
                SetProperty(ref _title, value);
            }
        }

        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            
        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            
        }
    }
}

ViewB.axaml

<UserControl 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:prism="http://prismlibrary.com/"
             prism:ViewModelLocator.AutoWireViewModel="True"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="AvaloniaTest.Views.ViewB" Background="Green">
  <TextBlock Text="{Binding Title}"></TextBlock>
</UserControl>

ViewBViewModel.cs

using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AvaloniaTest.ViewModels
{
    public class ViewBViewModel : ViewModelBase, INavigationAware
    {
        private string _title = "ViewB";

        public string Title
        {
            get => _title;
            set
            {
                SetProperty(ref _title, value);
            }
        }
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {
        }
    }
}

App.axaml

<prism:PrismApplication xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/"
             x:Class="AvaloniaTest.App"
             RequestedThemeVariant="Default">
             <!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->

    <Application.Styles>
        <FluentTheme />
    </Application.Styles>
</prism:PrismApplication>

App.axaml.cs

using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using AvaloniaTest.ViewModels;
using AvaloniaTest.Views;
using Prism.DryIoc;
using Prism.Ioc;

namespace AvaloniaTest;

public partial class App : PrismApplication
{
    public override void Initialize()
    {
        AvaloniaXamlLoader.Load(this);
        base.Initialize();
    }

    public override void OnFrameworkInitializationCompleted()
    {
        //if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
        //{
        //    desktop.MainWindow = new MainWindow
        //    {
        //        DataContext = new MainViewModel()
        //    };
        //}
        //else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
        //{
        //    singleViewPlatform.MainView = new MainView
        //    {
        //        DataContext = new MainViewModel()
        //    };
        //}

        base.OnFrameworkInitializationCompleted();
    }

    protected override AvaloniaObject CreateShell()
    {
        return Container.Resolve<MainWindow>();
    }

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.Register<MainView>();
        containerRegistry.RegisterForNavigation<ViewA,ViewAViewModel>(nameof(ViewA));
        containerRegistry.RegisterForNavigation<ViewB,ViewBViewModel>(nameof(ViewB));
    }
}

你可能感兴趣的:(Avalonia跨平台开发,Avalonia)