MvvmCross 跨平台应用开发——进阶篇_WPF导航局部切换

MvvmCross 跨平台应用开发——进阶篇_WPF导航局部切换

简言

书接上回,在 MvvmCross 跨平台应用开发——入门篇 中我们概述了MvvmCross框架的基础,并创建了基础开发模型包含Windows的WPF和Android的Xamarin.Android两个平台的应用程序,以及核心的Core程序集,构建一个跨平台的基础开发模板。这篇将通过细致的代码逻辑来讲解构建大型应程序的核心部件导航功能

主窗体配置

MvvmCross框架下 WPF 默认的 MainWindow 窗体并不能完美的实现主窗体的功能并且需要继承 MvxWindow 类才能够让框架识别。MainWindow 是没有对应的 VM 类的。这时我们就需要手动创建其他的窗体作为我们程序的主窗体。

首先我们将分别在 Core层 和 WPF层 创建 MainViewModel.csMainView.xaml

  • 先看 ViewModel 层,比较简单,首先MainViewModel类需要继承MvxNavigationViewModel类。然后声明我们需要的属性和命令以及命令实现方法。
using Microsoft.Extensions.Logging;
using MvvmCross.Commands;
using MvvmCross.Navigation;
using MvvmCross.ViewModels;
using MvvmCrossCore.ViewModels.Navigations;
using System.Threading.Tasks;

namespace MvvmCrossCore.ViewModels
{
    public class MainViewModel : MvxNavigationViewModel
    {
        public MainViewModel(ILoggerFactory logFactory, IMvxNavigationService navigationService) : base(logFactory, navigationService)
        {
            ShowToolsViewCommand = new MvxAsyncCommand(ShowToolsView);
            ShowSecondViewCommand = new MvxAsyncCommand(ShowSecondView);
        }

        public MvxNotifyTask LoadTask { get; private set; }
        public IMvxAsyncCommand ShowToolsViewCommand { get; private set; }
        public IMvxAsyncCommand ShowSecondViewCommand { get; private set; }

        public override void ViewAppeared()
        {
            base.ViewAppeared();
            LoadTask = MvxNotifyTask.Create(Load);
        }

        private async Task Load()
        {
            await NavigationService.Navigate<ToolsViewModel>();
        }

        Task ShowToolsView()
        {
            return NavigationService.Navigate<ToolsViewModel>();
        }

        Task ShowSecondView()
        {
            return NavigationService.Navigate<SecondViewModel>();
        }
    }
}

再来看View层,也很好理解,view层包含xaml和cs两部分。

  • 先看 cs 部分,不需要继承任何类删除原有的继承类,需要添加两个 Attribute
    • MvxWindowPresentation 框架的窗口呈现器,字面意思就是用来显示窗体的。
    • MvxViewFor(typeof(MainViewModel)) 绑定创建的ViewModel。
using MvvmCross.Platforms.Wpf.Presenters.Attributes;
using MvvmCross.ViewModels;
using MvvmCrossCore.ViewModels;

namespace MvvmCrossWPF.Views
{
    /// <summary>
    /// MainView.xaml 的交互逻辑
    /// </summary>
    [MvxWindowPresentation]
    [MvxViewFor(typeof(MainViewModel))]
    public partial class MainView
    {
        public MainView()
        {
            InitializeComponent();
        }
    }
}
  • UI布局,这里需要注意布局使用的 MvxWindow.ContentTemplate 标签 它是在 clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf 命名空间下的,一定要引入
    • 结构: ContentTemplate → DataTemplate → Grid
    • 重点: Grid标签中的 DataContext 属性值 DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" 懂WPF的同学都知道这是将数据绑定到UI上的方式
    • 重中之重:ContentPresenter(内容呈现器) 标签中的 Content 属性值 Content="{Binding Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" 这个关乎到我们的导航切换页面时,能否实现 “指哪打哪的效果”
    • views:MvxWindow 用来创建窗体。
<views:MvxWindow
    x:Class="MvvmCrossWPF.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    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:views="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
    Title="XXX"
    d:DesignHeight="350"
    d:DesignWidth="600"
    WindowState="Maximized"
    mc:Ignorable="d">
    
    <views:MvxWindow.ContentTemplate>
        <DataTemplate>
            <Grid DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150" />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>

                <StackPanel Grid.Column="0" Background="CornflowerBlue">
                    <Button
                        Margin="5"
                        Padding="5"
                        Command="{Binding ShowToolsViewCommand}"
                        CommandParameter="1"
                        Content="工具" />
                    <Button
                        Margin="5"
                        Padding="5"
                        Command="{Binding ShowSecondViewCommand}"
                        CommandParameter="1"
                        Content="Second 1st Child" />
                </StackPanel>

                <ContentPresenter
                    Grid.Column="1"
                    HorizontalAlignment="Stretch"
                    VerticalAlignment="Stretch"
                    Content="{Binding Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
            </Grid>
        </DataTemplate>
    </views:MvxWindow.ContentTemplate>

</views:MvxWindow>

子页面的配置

还是一样的先看ViewModel层,再看View层。

  • ViewModel,同样是需要继承 MvxNavigationViewModel 类 比较好理解
using Microsoft.Extensions.Logging;
using MvvmCross.Navigation;
using MvvmCross.ViewModels;

namespace MvvmCrossCore.ViewModels.Navigations
{
    public class ToolsViewModel : MvxNavigationViewModel
    {
        public ToolsViewModel(ILoggerFactory logFactory, IMvxNavigationService navigationService) : base(logFactory, navigationService)
        {
        }
        public string Title { get; set; } = "First View";

    }
}

View层,这一层就和主窗体有些不一样了

  • cs代码
    • WindowIdentifier 您可以通过该属性选择在哪个窗口中显示该视图。如果未提供标识符,则该视图将显示在最后打开的窗口中。
    • StackNavigation 视图类可以决定是否要使用堆栈导航或非堆栈导航来显示。默认值为真。
using MvvmCross.Platforms.Wpf.Presenters.Attributes;

namespace MvvmCrossWPF.Views.Navigations
{
    /// <summary>
    /// FirstView.xaml 的交互逻辑
    /// </summary>
    [MvxContentPresentation(WindowIdentifier = nameof(MainWindow), StackNavigation = false)]
    public partial class ToolsView
    {
        public ToolsView()
        {
            InitializeComponent();
        }
    }
}
  • UI 布局唯一的不同点在于 views:MvxWpfView 用来创建显示页面 这里是唯一需要注意的点。
<views:MvxWpfView
    x:Class="MvvmCrossWPF.Views.Navigations.ToolsView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    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:views="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">

    <WrapPanel HorizontalAlignment="Center">
        <Button Margin="10,5" Content="工具1" />
        <Button Margin="10,5" Content="工具1" />
        <Button Margin="10,5" Content="工具1" />
        <Button Margin="10,5" Content="工具1" />
        <Button Margin="10,5" Content="工具1" />
        <Button Margin="10,5" Content="工具1" />
        <Button Margin="10,5" Content="工具1" />
        <Button Margin="10,5" Content="工具1" />
        <Button Margin="10,5" Content="工具1" />
    </WrapPanel>
</views:MvxWpfView>
  • 效果图
    在这里插入图片描述
    在这里插入图片描述

详解

实现局部导航切换需要三个限定
1、VM类必须继承 MvxNavigationViewModel 类。
2、主窗体cs代码添加 [MvxWindowPresentation] [MvxViewFor(typeof(MainViewModel))] Attribute,xaml需要在 views:MvxWindow 标签中进行布局。
3、子页面cs代码添加 [MvxContentPresentation(WindowIdentifier = nameof(MainWindow), StackNavigation = false)] Attribute,xaml需要在 views:MvxWpfView 标签中进行布局。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑夜中的潜行者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值