티스토리 뷰

반응형

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

 

이번 포스팅에서는 TabControl에 Region을 설정하고 사용하는 방법에 대해서 알아 보겠습니다.

1. TabControl에 Region 설정해서 사용하기

먼저, 이전 포스팅에서 구현했던 내용을 TabControl로만 변경해 보겠습니다.

MainWindow.xaml

<Window
    x:Class="PrismStep5.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>
        <!--  TabControl에 Region 설정  -->
        <TabControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion">
            <TabControl.Resources>
                <!--  TabItem Header에 뷰모델 Header 프로퍼티 연결  -->
                <Style TargetType="TabItem">
                    <Setter Property="Header" Value="{Binding DataContext.Header}" />
                </Style>
            </TabControl.Resources>
        </TabControl>
    </Grid>
</Window>

실행

Test1View 버튼 클릭

Test2View 버튼 클릭

ContentControl과는 다르게, 새로운 TabItem이 추가되면서 각 각 화면을 표시할 수 있게 됩니다.

Back 버튼 클릭

첫번째 TabItem이 활성화가 되면서, OnNavigatedTo 이벤트가 발생합니다.

다만, TabControl이기 때문에 각 각의 TabItem을 클릭해서 활성화 시켰을 때는 OnNavigatedTo, OnNavigatedFrom을 발생시키지 않습니다.

Test2ViewModel 탭 클릭

2. IActiveAware

TabControl의 각 TabItem이 활성화가 될 때 뷰 모델에서 인지하고, 처리할 필요가 있는 경우에 사용하는 인터페이스입니다. 

  • bool IsActive { get; set; } 
    • 활성화가되면 true, 비활성화시 false로 변경됩니다.
    • 이 프로퍼티의 값이 변경되는 것을 감시하다가 값이 변경되면 원하는 작업을 처리하면 됩니다.
  • event EventHandler IsActiveChanged;
    • IsActive가 변경되면 발생되는 이벤트 입니다.
    • 다른 화면에서 이 화면의 활성 여부를 감시하기 위해서 사용합니다.

Test1ViewModel.cs

SetProperty() 메서드 뒤에 () => Message.Add(...)는 Prism BindableBase에 구현되어 있는 기본 기능입니다.
프로퍼티가 변경되면 실행될 Action을 미리 지정할 수 있습니다.
using Prism;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace PrismStep5.ViewModels
{
    /// <summary>
    /// IActiveAware 인터페이스를 추가합니다.
    /// </summary>
    public class Test1ViewModel : BindableBase, INavigationAware, IActiveAware
    {
        public string Header { get; set; }
        /// <summary>
        /// 액티브 체인지 이벤트 - IActiveAware
        /// </summary>
        public event EventHandler IsActiveChanged;
        private bool _isActive;
        /// <summary>
        /// IsActive 활성화 여부 프로퍼티 - IActiveAware
        /// </summary>
        public bool IsActive
        {
            get { return _isActive; }
            set { SetProperty(ref _isActive, value, () => Messages.Add($"{GetType().Name} IsActive : {IsActive}")); }
        }

        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 - {navigationContext.NavigationService.Journal.CurrentEntry}");
        }
        /// <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 클릭

OnNavigatedTo가 실행되기도 전에 IsActive가 false -> true로 변경된 것을 알 수 있습니다.

Test2View 클릭

Test1ViewModel이라는 이름의 TabItem을 클릭(Back 버튼 누르지 않음)

OnNavigatedFrom이 발생한 후에 IsActive가 false로 변경되었을 것으로 보이고,

이번에는 사용자가 직접 탭을 선택했기 때문에 바로 IsActive가 true로 변경된 것을 알 수 있습니다.

3. Region에 미리 특정 화면을 등록해 놓기

지금까지는 애플리케이션을 실행 시켰을 때 빈화면이 보이고, Test1View, Test2View 버튼을 눌러서 네비게이션을 시켜야 했습니다. 그러나, 일반적으로 빈 화면은 익숙하지 않겠죠?

MainWindowViewModel.cs

RegionManager를 이용해서 미리 특정 Region에 특정 화면을 등록해 놓으면, 해당 Region이 활성화되면, 등록된 화면을 자동으로 불러와서 출력해 주는 기능이 있습니다.

아래 소스를 참고하세요.

/// <summary>
/// 런타임 생성자
/// </summary>
/// <param name="regionManager"></param>
public MainWindowViewModel(IRegionManager regionManager)
    : this()
{
    //IRegionManager를 Injection 받아서 사용하기 위해 _regionManager에 연결합니다.
    _regionManager = regionManager;
    //ContentRegion에 Test1View를 등록 예약 시켜 놓습니다.
    _regionManager.RegisterViewWithRegion("ContentRegion", "Test1View");
}

실행

이렇게 미리 시작화면을 등록 시켜 놓았을 때 RequestNavigate를 호출하지 않았기 때문에, 뷰와 뷰모델이 인스턴스 된 후 IsActive 프로퍼티의 값만 변경됩니다.

4. 정리

  • RegionManager.RegisterViewWithRegion 메서드를 이용하면, 특정 Region에 미리 특정 뷰를 등록해 놓을 수 있습니다.
  • ViewModel에 INavigationAware, IActiveAware를 모두 사용할 수 있습니다.
  • RegionManager.RequestNavigate를 이용해서 미리 등록된 뷰를 특정 Region에 Navigation 시킬 수 있습니다.
  • ContentControl에 Region을 적용했을 때
    • 한번에 하나의 뷰만 볼 수 있습니다
    • GoBack(), GoForward() 메서드를 이용해서 탐색을 할 수 있습니다.
    • OnNavigatedTo, IsNavigationTarget, OnNavigatedFrom 메서드를 이용해서 탐색이 발생했을 때 사용자 로직을 추가할 수 있습니다.
  • TabControl에 Region을 적용했을 때
    • 한번에 하나의 뷰만 볼 수 있습니다.
    • 다른 화면으로의 전환은 TabItem Header를 클릭하는 것으로 빠르게 탐색 할 수 있습니다.
    • 탐색관련 메서드가 실행되지 않고, IsActive 프로퍼티의 변경에 의해서만 화면 활성화 여부를 알 수 있습니다.

5. 소스

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

 

GitHub - kaki104/WpfTest

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

github.com

 

반응형
댓글