This commit is contained in:
Wiesław Šoltés 2020-11-29 23:43:00 +01:00
Родитель 92ad3c65bd
Коммит 881add3461
26 изменённых файлов: 607 добавлений и 0 удалений

25
NavigationSample.sln Normal file
Просмотреть файл

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30711.63
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NavigationSample", "NavigationSample\NavigationSample.csproj", "{EF1DC80F-1657-4211-B986-22815421C120}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EF1DC80F-1657-4211-B986-22815421C120}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF1DC80F-1657-4211-B986-22815421C120}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF1DC80F-1657-4211-B986-22815421C120}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF1DC80F-1657-4211-B986-22815421C120}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {35F94514-63C1-4827-B525-160DDBA8393D}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,13 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:NavigationSample"
x:Class="NavigationSample.App">
<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>
<Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
</Application.Styles>
</Application>

Просмотреть файл

@ -0,0 +1,29 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using NavigationSample.ViewModels;
using NavigationSample.Views;
namespace NavigationSample
{
public class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel(),
};
}
base.OnFrameworkInitializationCompleted();
}
}
}

Двоичные данные
NavigationSample/Assets/avalonia-logo.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 172 KiB

Просмотреть файл

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>NavigationSample</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Folder Include="Models\" />
<AvaloniaResource Include="Assets\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.999-cibuild0012072-beta" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.999-cibuild0012072-beta" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.999-cibuild0012072-beta" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.999-cibuild0012072-beta" />
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.0-preview6" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,17 @@
using Avalonia;
using Avalonia.ReactiveUI;
namespace NavigationSample
{
class Program
{
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace()
.UseReactiveUI();
}
}

Просмотреть файл

@ -0,0 +1,32 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using NavigationSample.ViewModels;
namespace NavigationSample
{
public class ViewLocator : IDataTemplate
{
public bool SupportsRecycling => false;
public IControl Build(object data)
{
var name = data.GetType().FullName.Replace("ViewModel", "View");
var type = Type.GetType(name);
if (type != null)
{
return (Control)Activator.CreateInstance(type);
}
else
{
return new TextBlock { Text = "Not Found: " + name };
}
}
public bool Match(object data)
{
return data is ViewModelBase;
}
}
}

Просмотреть файл

@ -0,0 +1,6 @@
namespace NavigationSample.ViewModels
{
public class DialogViewModel : ViewModelBase
{
}
}

Просмотреть файл

@ -0,0 +1,6 @@
namespace NavigationSample.ViewModels
{
public class HomeViewModel : ViewModelBase
{
}
}

Просмотреть файл

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Input;
using ReactiveUI;
namespace NavigationSample.ViewModels
{
public class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
NavigationManagerViewModel.Register();
NavigationManagerViewModel.Instance.NavigatePane(new PaneViewModel());
NavigationManagerViewModel.Instance.NavigateContent(new HomeViewModel());
Navigation = NavigationManagerViewModel.Instance;
}
public NavigationManagerViewModel Navigation { get; }
}
}

Просмотреть файл

@ -0,0 +1,155 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using ReactiveUI;
namespace NavigationSample.ViewModels
{
public class NavigationManagerViewModel : ViewModelBase
{
public static NavigationManagerViewModel Instance { get; private set; }
public static void Register()
{
Instance = new NavigationManagerViewModel();
}
private ObservableCollection<ViewModelBase> _contentStack;
private ObservableCollection<ViewModelBase> _dialogStack;
private ViewModelBase _currentPane;
private ViewModelBase _currentContent;
private ViewModelBase _currentDialog;
private NavigationManagerViewModel()
{
_contentStack = new ObservableCollection<ViewModelBase>();
_dialogStack = new ObservableCollection<ViewModelBase>();
ClosePaneCommand = ReactiveCommand.Create<ViewModelBase>(x => ClosePane(x));
CloseContentCommand = ReactiveCommand.Create<ViewModelBase>(x => CloseContent(x));
CloseDialogCommand = ReactiveCommand.Create<ViewModelBase>(x => CloseDialog(x));
}
public ObservableCollection<ViewModelBase> ContentStack
{
get => _contentStack;
private set => this.RaiseAndSetIfChanged(ref _contentStack, value);
}
public ObservableCollection<ViewModelBase> DialogStack
{
get => _dialogStack;
private set => this.RaiseAndSetIfChanged(ref _dialogStack, value);
}
public ViewModelBase CurrentPane
{
get => _currentPane;
private set => this.RaiseAndSetIfChanged(ref _currentPane, value);
}
public ViewModelBase CurrentContent
{
get => _currentContent;
private set => this.RaiseAndSetIfChanged(ref _currentContent, value);
}
public ViewModelBase CurrentDialog
{
get => _currentDialog;
private set => this.RaiseAndSetIfChanged(ref _currentDialog, value);
}
public ICommand ClosePaneCommand { get; }
public ICommand CloseContentCommand { get; }
public ICommand CloseDialogCommand { get; }
private void ClosePane(ViewModelBase pane)
{
CurrentPane = null;
}
private void CloseContent(ViewModelBase content)
{
_contentStack.Remove(content);
CurrentContent = null;
}
private void CloseDialog(ViewModelBase dialog)
{
_dialogStack.Remove(dialog);
CurrentDialog = null;
}
private void ClearContent()
{
_contentStack.Clear();
CurrentContent = null;
}
private void ClearDialog()
{
_dialogStack.Clear();
CurrentDialog = null;
}
public void NavigatePane(ViewModelBase pane)
{
CurrentPane = pane;
}
public void NavigateContent(ViewModelBase content)
{
CurrentContent = content;
_contentStack.Add(content);
}
public void NavigateDialog(ViewModelBase dialog)
{
CurrentDialog = dialog;
_dialogStack.Add(dialog);
}
public void GoBackContent()
{
if (_contentStack.Count <= 1)
{
return;
}
var last = _contentStack.LastOrDefault();
if (last is { })
{
_contentStack.Remove(last);
var back = _contentStack.LastOrDefault();
if (back is { })
{
CurrentContent = back;
}
}
}
public void GoBackDialog()
{
if (_dialogStack.Count <= 1)
{
return;
}
var last = _dialogStack.LastOrDefault();
if (last is { })
{
_dialogStack.Remove(last);
var back = _dialogStack.LastOrDefault();
if (back is { })
{
CurrentDialog = back;
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
using System.Windows.Input;
using ReactiveUI;
namespace NavigationSample.ViewModels
{
public class PaneViewModel : ViewModelBase
{
public PaneViewModel()
{
GoBackContentCommand = ReactiveCommand.Create(
() => NavigationManagerViewModel.Instance.GoBackContent());
GoBackDialogCommand = ReactiveCommand.Create(
() => NavigationManagerViewModel.Instance.GoBackDialog());
HomeCommand = ReactiveCommand.Create(
() => NavigationManagerViewModel.Instance.NavigateContent(new HomeViewModel()));
SettingsCommand = ReactiveCommand.Create(
() => NavigationManagerViewModel.Instance.NavigateContent(new SettingsViewModel()));
DialogCommand = ReactiveCommand.Create(
() => NavigationManagerViewModel.Instance.NavigateDialog(new DialogViewModel()));
}
public ICommand GoBackContentCommand { get; }
public ICommand GoBackDialogCommand { get; }
public ICommand HomeCommand { get; }
public ICommand SettingsCommand { get; }
public ICommand DialogCommand { get; }
}
}

Просмотреть файл

@ -0,0 +1,6 @@
namespace NavigationSample.ViewModels
{
public class SettingsViewModel : ViewModelBase
{
}
}

Просмотреть файл

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
using ReactiveUI;
namespace NavigationSample.ViewModels
{
public class ViewModelBase : ReactiveObject
{
}
}

Просмотреть файл

@ -0,0 +1,12 @@
<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:NavigationSample.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:DataType="vm:DialogViewModel" x:CompileBindings="True"
x:Class="NavigationSample.Views.DialogView">
<Panel>
<TextBlock Text="Dialog" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Panel>
</UserControl>

Просмотреть файл

@ -0,0 +1,18 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace NavigationSample.Views
{
public class DialogView : UserControl
{
public DialogView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
<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:NavigationSample.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:DataType="vm:HomeViewModel" x:CompileBindings="True"
x:Class="NavigationSample.Views.HomeView">
<Panel>
<TextBlock Text="Home" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Panel>
</UserControl>

Просмотреть файл

@ -0,0 +1,18 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace NavigationSample.Views
{
public class HomeView : UserControl
{
public HomeView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

Просмотреть файл

@ -0,0 +1,20 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:NavigationSample.ViewModels;assembly=NavigationSample"
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="NavigationSample.Views.MainWindow"
Icon="/Assets/avalonia-logo.ico"
Title="NavigationSample"
WindowStartupLocation="CenterScreen"
Width="900" Height="600"
x:DataType="vm:MainWindowViewModel" x:CompileBindings="True">
<Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<ContentControl Content="{Binding Navigation}"/>
</Window>

Просмотреть файл

@ -0,0 +1,22 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace NavigationSample.Views
{
public class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

Просмотреть файл

@ -0,0 +1,46 @@
<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:NavigationSample.ViewModels"
xmlns:i="using:Avalonia.Xaml.Interactivity"
xmlns:ia="using:Avalonia.Xaml.Interactions.Core"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:DataType="vm:NavigationManagerViewModel" x:CompileBindings="True"
x:Class="NavigationSample.Views.NavigationManagerView">
<Panel>
<!-- SplitView -->
<DockPanel x:Name="SplitView">
<Panel x:Name="Pane" DockPanel.Dock="Left" IsVisible="{Binding !!CurrentPane}">
<!-- Pane -->
<ContentControl Content="{Binding CurrentPane}"/>
</Panel>
<!-- Content -->
<Panel x:Name="Content">
<ContentControl Content="{Binding CurrentContent}"/>
</Panel>
</DockPanel>
<!-- Dialog -->
<Panel IsVisible="{Binding !!CurrentDialog}">
<Panel x:Name="Overlay" Background="#7F000000">
<i:Interaction.Behaviors>
<ia:EventTriggerBehavior EventName="PointerPressed">
<ia:InvokeCommandAction Command="{Binding CloseDialogCommand}" CommandParameter="{Binding CurrentDialog}" />
</ia:EventTriggerBehavior>
</i:Interaction.Behaviors>
</Panel>
<Panel x:Name="Dialog" MaxWidth="500" MaxHeight="400">
<Border Background="WhiteSmoke" CornerRadius="4"/>
<ContentControl Content="{Binding CurrentDialog}"/>
</Panel>
</Panel>
</Panel>
</UserControl>

Просмотреть файл

@ -0,0 +1,18 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace NavigationSample.Views
{
public class NavigationManagerView : UserControl
{
public NavigationManagerView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

Просмотреть файл

@ -0,0 +1,18 @@
<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:NavigationSample.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:DataType="vm:PaneViewModel" x:CompileBindings="True"
x:Class="NavigationSample.Views.PaneView">
<Panel Background="LightGray" MinWidth="200">
<StackPanel>
<Button Content="GoBackContent" Command="{Binding GoBackContentCommand}" Margin="4" HorizontalAlignment="Stretch"/>
<Button Content="GoBackDialog" Command="{Binding GoBackDialogCommand}" Margin="4" HorizontalAlignment="Stretch"/>
<Button Content="Home" Command="{Binding HomeCommand}" Margin="4" HorizontalAlignment="Stretch"/>
<Button Content="Settings" Command="{Binding SettingsCommand}" Margin="4" HorizontalAlignment="Stretch"/>
<Button Content="Dialog" Command="{Binding DialogCommand}" Margin="4" HorizontalAlignment="Stretch"/>
</StackPanel>
</Panel>
</UserControl>

Просмотреть файл

@ -0,0 +1,18 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace NavigationSample.Views
{
public class PaneView : UserControl
{
public PaneView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
<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:NavigationSample.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:DataType="vm:SettingsViewModel" x:CompileBindings="True"
x:Class="NavigationSample.Views.SettingsView">
<Panel>
<TextBlock Text="Settings" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Panel>
</UserControl>

Просмотреть файл

@ -0,0 +1,18 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace NavigationSample.Views
{
public class SettingsView : UserControl
{
public SettingsView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}