티스토리 뷰

반응형

2022.11.30 - [WPF .NET] - Prism Library를 사용하는 개발자를 위한 안내 Part6 - TabControl Region Navigation

2022.11.25 - [WPF .NET] - Prism Library를 사용하는 개발자를 위한 안내 Part5 - Region & ContentControl Region Navigation

2022.11.18 - [WPF .NET] - Prism Library를 사용하는 개발자를 위한 안내 Part4 - Register Types

2022.11.15 - [WPF .NET] - Prism Library를 사용하는 개발자를 위한 안내 Part3 - DelegateCommand

2022.10.28 - [WPF .NET] - Prism Library를 사용하는 개발자를 위한 안내 Part2 - 프로젝트 구성 살펴 보기

2022.10.27 - [WPF .NET] - Prism Library를 사용하는 개발자를 위한 안내 Part1

1. Prism Library에서 Navigation 사용하기

Navigation이란 인터넷 브라우저에서 웹 페이지에서 링크를 클릭해서 다른 웹 페이지로 이동하고, Back key를 눌러서 이전 페이지로 돌아가는 일련의 과정을 이야기합니다.

 

WPF에서는 Frame이라는 컨트롤을 이용하면, Page.xaml들을 인터넷 브라우저에서 사용하는 것과 같이 Navigation 시키고, Navigation Back을 시킬 수 있습니다. 그런데, 이 컨트롤을 이용한 Navigation을 실무 프로젝트에서 사용하는 것은 약간 불편합니다.

Frame 컨트롤을 이용하여 Navigation하는 간단한 예제는 여기를 참고하시기 바랍니다.

Prism Library에서는 Region이라는 논리 영역을 지정하고, 그 영역 내부에서 Navigation 시킬 수 있는 기능을 제공합니다.

아래 그림을 보면 TabControl을 "Edit Region"이라는 이름으로 정의하고, 아래 코드를 실행하면 Test1View를 인스턴스 시켜서, "Edit Region" TabControl의 TabItem을 하나 추가하고, 그 곳에 Test1View를 넣은 후 활성화를 시켜줍니다.

RegionManager.RequestNavigate("Edit Region", "Test1View");

Prism Library에서 Region Navigation을 어떻게 사용하는지 좀더 자세하게 알아 보도록 하겠습니다.

2. Region을 정의 할 수 있는 컨트롤

Prism Library에는 Region을 정의할 수 있는 RegionAdapter가 3개 있습니다.. 그 외에 컨트롤에 Region을 정의하고 사용하려면, RegionAdapterBase 클래스를 상속 받은 Adapter 클래스를 생성해서 사용하면 되며, 추후 이 부분에 대해서 다루도록 하겠습니다.

아래 RegionAdapter는 특정 컨트롤에 Region을 정의하면 자동으로 적용됩니다.
  • ContentControlRegionAdapter
    • 컨트롤 : ContentControl과 ContentControl을 상속 받은 컨트롤
    • 한번에 한개의 화면만을 보여줄 수 있습니다. 
    • Navigate, Back, Forward
    • 뷰모델에 INavigationAware 인터페이스를 구현해서, 네비게이션 관련 처리를 할 수 있습니다.
  • SelectorRegionAdapter
    • 컨트롤 : Selector를 상속 받은 컨트롤 예) TabControl, ListBox
    • Select가 가능 합니다.
    • 뷰모델에 IActiveAware 인터페이스를 구현해서, 활성화 여부를 알 수 있습니다.
  • ItemsControlRegionAdapter
    • 컨트롤 : ItemsControl과 ItemsControl을 상속 받은 컨트롤
    • Select없이 나열합니다.

3. ContentControl에 Region 사용하기

MainWindow.xaml

간단하게 아래와 같은 화면을 만들어 줍니다.

<Window
    x:Class="PrismStep4.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:prism="http://prismlibrary.com/"
    Title="{Binding Title}"
    Width="525"
    Height="350"
    prism:ViewModelLocator.AutoWireViewModel="True">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <Button
                Command="{Binding NavigationCommand}"
                CommandParameter="Test1View"
                Content="Test1View" />
            <Button
                Command="{Binding NavigationCommand}"
                CommandParameter="Test2View"
                Content="Test2View" />
            <Button
                Command="{Binding NavigationCommand}"
                CommandParameter="Back"
                Content="Back" />
        </StackPanel>
        <ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion" />
    </Grid>
</Window>

MainWindowViewModel.cs

using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using System.Windows.Input;

namespace PrismStep4.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        private string _title = "Prism Application";
        /// <summary>
        /// Region관리자
        /// </summary>
        private readonly IRegionManager _regionManager;
        /// <summary>
        /// 타이틀
        /// </summary>
        public string Title
        {
            get => _title;
            set => SetProperty(ref _title, value);
        }
        /// <summary>
        /// 네비게이션 커맨드
        /// </summary>
        public ICommand NavigationCommand { get; set; }
        /// <summary>
        /// 기본 생성자
        /// </summary>
        public MainWindowViewModel()
        {
            NavigationCommand = new DelegateCommand<string>(OnNavigation);
        }
        /// <summary>
        /// 런타임 생성자
        /// </summary>
        /// <param name="regionManager"></param>
        public MainWindowViewModel(IRegionManager regionManager)
            : this()
        {
            //IRegionManager를 Injection 받아서 사용하기 위해 _regionManager에 연결합니다.
            _regionManager = regionManager;
        }
        /// <summary>
        /// NavigationCommand의 실행 메서드
        /// </summary>
        /// <param name="para"></param>
        private void OnNavigation(string para)
        {
            switch (para)
            {
                //Back이란 문자열이 들어오면..
                case "Back":
                    {
                        //Back을 구현하기 위해서 ContentRegion의 Journal을 가져오고, 뒤로가기가 가능한지 확인 후 실행
                        IRegionNavigationJournal journal = _regionManager.Regions["ContentRegion"]
                                                                .NavigationService.Journal;
                        if (journal.CanGoBack)
                        {
                            journal.GoBack();
                        }
                    }
                    break;
                //그외 일반 문자열이 들어오면    
                default:
                    //ContentRegion에 para가 지정하는 화면으로 네비게이트 해라
                    _regionManager.RequestNavigate("ContentRegion", para);
                    break;
            }
        }
    }
}

그리고, 간단한 Test1View와 Test2View를 추가했습니다. 

가장 중요한 네비게이션 가능한 화면 등록작업

App.xaml.cs

using Prism.Ioc;
using PrismStep4.Views;
using System.Windows;

namespace PrismStep4
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            //네비게이션할 화면 등록
            containerRegistry.RegisterForNavigation<Test1View>();
            containerRegistry.RegisterForNavigation<Test2View>();
        }
    }
}

실행

Test1View 버튼 클릭

Test2View 버튼 클릭

Back 버튼 클릭

Back 버튼 다시 클릭해도 더 이상 뒤로갈 수 없기 때문에 이동하지 않습니다.

4. INavigationAware를 이용해서 이동 상황 처리하기

Test1View.xaml

<UserControl
    x:Class="PrismStep4.Views.Test1View"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:prism="http://prismlibrary.com/"
    prism:ViewModelLocator.AutoWireViewModel="True">
    <Grid>
        <ListBox
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            ItemsSource="{Binding Messages}" />
    </Grid>
</UserControl>

Test1ViewModel.cs

뷰모델에 INavigationAware 인터페이스를 구현하면, OnNavigatedTo, IsNavigationTarget, OnNavigatedFrom 메서드들이 추가됩니다.

네비게이트가될 때 실제로 어떻게 동작되는지 바로 알 수 있게 화면을 구성했습니다.

using Prism.Mvvm;
using Prism.Regions;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace PrismStep4.ViewModels
{
    public class Test1ViewModel : BindableBase, INavigationAware
    {
        public string Header { get; set; }
        private IList<string> _messages = new ObservableCollection<string>();
        /// <summary>
        /// 메시지 목록
        /// </summary>
        public IList<string> Messages
        {
            get => _messages;
            set => SetProperty(ref _messages, value);
        }
        public Test1ViewModel()
        {
            Header = GetType().Name;
            Messages.Add(Header);
        }
        /// <summary>
        /// 네비게이트 To
        /// </summary>
        /// <param name="navigationContext"></param>
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            Messages.Add($"{GetType().Name} OnNavigatedTo");
        }
        /// <summary>
        /// 네비게이트 가능 여부
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <returns></returns>
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }
        /// <summary>
        /// 네비게이트 From
        /// </summary>
        /// <param name="navigationContext"></param>
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            Messages.Add($"{GetType().Name} OnNavigatedFrom");
        }
    }
}

실행 후 Test1View 클릭

Test2View 클릭

Back 버튼 클릭

Test2View 버튼을 클릭했을 때 OnNavigatedFrom이 실행되었다는 것을 알 수 있습니다. 물론 눈으로 확인을 할 수는 없었지만, 기록이 남아있으니 확인은 가능합니다. 그리고, Back으로 왔다고 하더라도, OnNavigatedTo 메서드가 호출되는 것을 알 수 있습니다.

5. 소스

WpfTest/PrismStep4 at master · kaki104/WpfTest (github.com)

 

GitHub - kaki104/WpfTest

Contribute to kaki104/WpfTest development by creating an account on GitHub.

github.com

 

반응형
댓글