Задать вопрос
@WSGlebKavash

Как сделать постраничную навигацию в Avalonia UI MVVM?

MainWindow
MainWindow.axaml
<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="using:MultiPageApp.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="MultiPageApp.Views.MainWindow"
        x:DataType="vm:MainWindowViewModel"
        Icon="/Assets/avalonia-logo.ico"
        Title="{Binding CurrentPage.Title}">

    <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>

    <ContentPresenter Content="{Binding CurrentPage}"></ContentPresenter>

</Window>
MainWindowViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;

namespace MultiPageApp.ViewModels;

public partial class MainWindowViewModel : WindowViewModel
{
    public string Greeting { get; } = "Welcome to Avalonia!";
    [ObservableProperty]
    private PageViewModel _currentPage;
}
LoginPage
LoginPageView.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:vm="using:MultiPageApp.ViewModels"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="MultiPageApp.Views.LoginPageView"
             x:DataType="vm:LoginPageViewModel">
    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
            <TextBlock FontSize="21" TextAlignment="Right" Text="Логин:"></TextBlock>
            <TextBox FontSize="21" Width="200"></TextBox>
        </StackPanel>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
            <TextBlock FontSize="21" TextAlignment="Right" Text="Пароль:"></TextBlock>
            <TextBox FontSize="21" Width="200"></TextBox>
        </StackPanel>
        <Button HorizontalAlignment="Stretch" Content="Войти" Command="{Binding Login}"></Button>
    </StackPanel>
</UserControl>
LoginPageViewModel.cs
namespace MultiPageApp.ViewModels;

public class LoginPageViewModel : PageViewModel
{
    public LoginPageViewModel()
    {
        Title = "Авторизация";
    }
    public void Login()
    {
        App.CurrentPage = new AdminPageViewModel();
    }
}
AdminPage
AdminPageView.axaml
<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:vm="using:MultiPageApp.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:DataType="vm:AdminPageViewModel"
             x:Class="MultiPageApp.Views.AdminPageView">
    Welcome to Avalonia!
</UserControl>
AdminPageViewModel.cs
namespace MultiPageApp.ViewModels;

public class AdminPageViewModel : PageViewModel
{
    public AdminPageViewModel()
    {
        Title = "Интерфейс администратора";
    }
}
Служебные
App.axaml.cs
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
using System.Linq;
using Avalonia.Markup.Xaml;
using MultiPageApp.ViewModels;
using MultiPageApp.Views;

namespace MultiPageApp;

public partial class App : Application
{
    public static PageViewModel CurrentPage { get; set; }
    public override void Initialize()
    {
        AvaloniaXamlLoader.Load(this);
    }

    public override void OnFrameworkInitializationCompleted()
    {
        if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
        {
            // Avoid duplicate validations from both Avalonia and the CommunityToolkit. 
            // More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
            DisableAvaloniaDataAnnotationValidation();
            LoginPageViewModel loginViewModel = new LoginPageViewModel();
            CurrentPage = loginViewModel;
            MainWindowViewModel mainViewModel = new MainWindowViewModel() { CurrentPage = CurrentPage };
            desktop.MainWindow = new MainWindow
            {
                DataContext = mainViewModel,
            };
        }

        base.OnFrameworkInitializationCompleted();
    }

    private void DisableAvaloniaDataAnnotationValidation()
    {
        // Get an array of plugins to remove
        var dataValidationPluginsToRemove =
            BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();

        // remove each entry found
        foreach (var plugin in dataValidationPluginsToRemove)
        {
            BindingPlugins.DataValidators.Remove(plugin);
        }
    }
}
ViewLocator.cs
using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using MultiPageApp.ViewModels;

namespace MultiPageApp;

public class ViewLocator : IDataTemplate
{
    public Control? Build(object? param)
    {
        if (param is null)
            return null;

        var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
        var type = Type.GetType(name);

        if (type != null)
        {
            Control currentControl = (Control)Activator.CreateInstance(type)!;
            currentControl.DataContext = param;
            return currentControl;
        }

        return new TextBlock { Text = "Not Found: " + name };
    }

    public bool Match(object? data)
    {
        return data is ViewModelBase;
    }
}
В WPF реализовать постраничную навигацию очень просто. Для этого там есть инструменты <Frame> и NavigationService.
В Avalonia UI для смены страниц (представлений) используется <ContentPresentor>. Однако нет возможности использовать постраничную навигацию. Если навигация будет в окне, то всё работает. Но переход между страницами не доступен. Я попробовал использовать статическое свойство CurrentPage, но Notify не обрабатывает изменения корректно.
Как реализовать постраничную навигацию при помощи кнопок, расположенных непосредственно внутри представлений?
  • Вопрос задан
  • 33 просмотра
Подписаться 1 Простой Комментировать
Помогут разобраться в теме Все курсы
  • Учебный центр IBS
    SDP-030_PRG Продвинутая разработка в Microsoft .NET
    1 неделя
    Далее
  • Ulearn.me
    Проектирование на языке C#
    1 неделя
    Далее
  • Ulearn.me
    Основы программирования на примере C#. Часть 2
    1 неделя
    Далее
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы