MainWindowMainWindow.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.csusing CommunityToolkit.Mvvm.ComponentModel;
namespace MultiPageApp.ViewModels;
public partial class MainWindowViewModel : WindowViewModel
{
public string Greeting { get; } = "Welcome to Avalonia!";
[ObservableProperty]
private PageViewModel _currentPage;
}
LoginPageLoginPageView.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.csnamespace MultiPageApp.ViewModels;
public class LoginPageViewModel : PageViewModel
{
public LoginPageViewModel()
{
Title = "Авторизация";
}
public void Login()
{
App.CurrentPage = new AdminPageViewModel();
}
}
AdminPageAdminPageView.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.csnamespace MultiPageApp.ViewModels;
public class AdminPageViewModel : PageViewModel
{
public AdminPageViewModel()
{
Title = "Интерфейс администратора";
}
}
СлужебныеApp.axaml.csusing 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.csusing 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 не обрабатывает изменения корректно.
Как реализовать постраничную навигацию при помощи кнопок, расположенных непосредственно внутри представлений?