środa, 7 grudnia 2011

Prism View Navigation - Region Navigation

Region Navigation to jeden z rodzajów View Navigation. Mówiąc najprościej jest to podmiana widoku aktualnie wyświetlanego w danym regionie na inny widok.

W Prism mamy do dyspozycji bardzo prostą metodę RequestNavigate. Można ją wywołać na dwa sposoby:
  • za pośrednictwem klasy Region:

Code:
            IRegion myRegion = region;
            myRegion.RequestNavigate("Name_of_view");
Metoda w tym przypadku przyjmuje tylko nazwę widoku który ma zostać wyświetlony w regionie.
  •  za pośrednictwem klasy IRegionManager:

Code:
IRegionManager regionManager = rm;
region.Manager.RequestNavigate(RegionNames.Content, new Uri("View", UriKind.Relative));
W tym przypadku podajemy region w którym ma zostać wyświetlony widok jak i jego nazwę.

W tym przykładzie pokażę w jaki sposób skorzystać z drugiej wersji, czyli za pomocą RegionManagera - co wydaje mi się, daje większe możliwości i większą elastyczność.

Na początek struktura projektu który będziemy tworzyć:


Aplikacja będzie prezentowała się w następujący sposób:






Po kliknięciu w przycisk Moduł A zostanie wyświetlona zawartość modułu A, a w Module B Modułu B - prosta sprawa :).

Myślę że nie będę więcej wklejać kodu, który można znaleźć w poprzednich postach z cyklu Prism. Tak więc tylko najważniejsze części kodu oraz ich opis.

Główne okno aplikacji:


Code:
<Window x:Class="Sample_application_1.Shell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="clr-namespace:Microsoft.Practices.Prism.Regions;assembly=Microsoft.Practices.Prism"
        xmlns:Core="clr-namespace:Core;assembly=Core" Title="Shell" Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        
        <StackPanel prism:RegionManager.RegionName="{x:Static Core:RegionNames.ToolbarRegion}" 
                    Grid.Row="0" Orientation="Horizontal"/>
        
        <ContentControl prism:RegionManager.RegionName="{x:Static Core:RegionNames.ContentRegion}" 
                        Grid.Row="1"/>
    </Grid>
</Window>

Tak więc dwa regiony: pierwszy będzie zawierać przyciski nawigacji, drugi treść naszych widoków.

Jako że potrzebujemy wspólnego mechanizmu nawigacji stworzymy w bibliotece Core klasę ApplicationCommands:


Code:
using Microsoft.Practices.Prism.Commands;

namespace Core
{
    public class ApplicationCommands
    {
        public static CompositeCommand NavigationCommand = new CompositeCommand();
    }
}

Wejdźmy do modułu A:


Code:
using Core;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Unity;
using ModuleA.Navigation;

namespace ModuleA
{
    public class ModuleAModule : IModule
    {
        private readonly IRegionManager _regionManager;
        private readonly IUnityContainer _container;

        public ModuleAModule(IRegionManager regionManager, IUnityContainer container)
        {
            _regionManager = regionManager;
            _container = container;
        }

        public void Initialize()
        {
            _regionManager.RegisterViewWithRegion(RegionNames.ToolbarRegion, typeof (ButtonModuleA));
            _container.RegisterType<object, ModuleA>(typeof(ModuleA).FullName);
        }
    }
}

Ważniejsze aspekty tego co tutaj zostało wykonane:
  • w konstruktorze wstrzykujemy sobie potrzebne serwisy - kontener oraz region manager
  • standardowo za pomocą ViewDiscovery dodajemy nasz przycisk do Toolbara
  • Najważniejsze: rejestrujemy nasz widok A w kontenerze jako reprezentację typu object. Jest to bardzo ważne i jeżeli chcemy skorzystać z dobrodziejstwa nawigacji musimy w ten sposób zarejestrować nasz widok. 
Zobaczmy następnie jaki kod zawiera ViewModel:


Code:
using Core;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.Regions;

namespace ModuleA
{
    public class ModuleAViewModel
    {
    }
}

Właściwie to nic nie ma tutaj ciekawego. Tak samo będzie wyglądać VM drugiego modułu.

Chcemy aby nasz model nawigacji nie był związany z konkretnym widokiem. Implementacja poruszania się po naszej aplikacji zostanie stworzona w VM Shell-a. Zobaczmy więc na kod który znajduje się w Shell-u:


Code:
using Core;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.Regions;

namespace Sample_application_1
{
    public class ShellViewModel
    {
        private readonly IRegionManager _regionManager;
        public DelegateCommand<object> NavigationCommand { get; private set; } 

        public ShellViewModel(IRegionManager regionManager)
        {
            _regionManager = regionManager;
            NavigationCommand = new DelegateCommand<object>(navigationPath =>
                                                                {
                                                                    if (navigationPath != null)
                                                                    {
                                                                        regionManager.RequestNavigate(RegionNames.ContentRegion, navigationPath.ToString());
                                                                    }
                                                                });
            ApplicationCommands.NavigationCommand.RegisterCommand(NavigationCommand);
        }
    }
}


Kolejno idąc tokiem kodu:
  • tworzymy deklarację komendy NavigateCommand która ma za zadanie przenieść nas do odpowiedniego modułu
  • W konstruktorze tworzymy ją i za pomocą RequestNavigate przenosimy się do odpowiedniego widoku.
  • Jednym z parametrów metody jest navigationPath, która zostanie przysłana jako parametr komendy a decyduje ona o adresie widoku do którego chcemy się przenieść
  • Rejestrujemy naszą komendę w CompositeCommand NavigationCommand

Widok przycisku Modułu A:


Code:
<UserControl x:Class="ModuleA.Navigation.ButtonModuleA"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             xmlns:Core="clr-namespace:Core;assembly=Core" 
             xmlns:ModuleA="clr-namespace:ModuleA">
    <Grid>
        <Button Content="Moduł A" Command="{x:Static Core:ApplicationCommands.NavigationCommand}" 
                CommandParameter="{x:Type ModuleA:ModuleA}"/>
    </Grid>
</UserControl>

Bindujemy się do naszej komendy, a następnie jako parametr przekazujemy nazwę widoku, pobraną z enuma:


Code:
namespace ModuleA
{
    public enum ViewType
    {
        ModuleA
    }
}


Teraz możemy włączyć naszą aplikację i przemieszczać się pomiędzy widokami.

Brak komentarzy:

Prześlij komentarz