두 페이지 간의 탐색 구현

앱에서 기본 피어 투 피어 탐색을 할 수 있도록 프레임과 페이지를 사용하는 방법을 알아봅니다.

peer to peer navigation

거의 모든 앱에는 페이지 간 탐색이 필요합니다. 단일 콘텐츠 페이지가 있는 간단한 앱에도 일반적으로 탐색이 필요한 설정 페이지가 있습니다. 이 문서에서는 앱에 XAML Page 을 추가하고 Frame 페이지 간 탐색을 사용하는 기본 사항을 안내합니다.

Important

이 예제에서는 Microsoft Visual Studio의 빈 앱 템플릿을 사용합니다. Windows 앱 SDK/WinUI 3 앱 및 UWP 앱용 템플릿에는 차이가 있으므로 앱 유형에 맞는 탭을 선택해야 합니다.

1. 비어 있는 앱 만들기

Visual Studio에서 빈 앱을 만들려면

  1. 개발 컴퓨터를 설정하려면 Windows 앱 SDK용 도구 설치를 참조하세요.
  2. Microsoft Visual Studio 시작 창에서, 새 프로젝트 만들기를 선택하거나 Visual Studio 메뉴에서 파일>신규>프로젝트를 선택합니다.
  3. 새 프로젝트 만들기 대화 상자의 드롭다운 필터에서, C# 또는 C++, Windows, 및 WinUI를 각각 선택합니다.
  4. 비어 있는 앱, 패키지됨(데스크톱의 WinUI 3) 프로젝트 템플릿을 선택하고 다음을 클릭합니다. 이 템플릿은 WinUI 3 기반 사용자 인터페이스를 갖춘 데스크톱 앱을 만듭니다.
  5. 프로젝트 이름 상자에서, BasicNavigation를 입력한 후, 만들기를 클릭합니다.
  6. 프로그램을 실행하려면 디버그>디버깅 시작 을 메뉴에서 선택하거나 F5 키를 누릅니다. 개발 컴퓨터에서 솔루션을 빌드하고 실행하여 앱이 오류 없이 실행되는지 확인합니다. 빈 페이지가 표시됩니다.
  7. 디버깅을 중지하고 Visual Studio로 돌아가려면 앱을 종료하거나, 메뉴에서 디버깅 중지를 클릭합니다.
  8. 제거할 예제 코드가 있는 템플릿은 MainWindow.xamlMainWindow 코드 숨김 파일에 위치합니다.

자세한 내용은 첫 번째 WinUI 3(Windows 앱 SDK) 프로젝트 만들기를 참조하세요.

2. 프레임을 사용하여 페이지 간 이동

앱에 여러 페이지가 있는 경우 프레임 을 사용하여 페이지 사이를 탐색합니다. 이 Frame 클래스에서는 Navigate, GoBack, 및 GoForward같은 다양한 탐색 메서드와 BackStack, ForwardStack, 및 BackStackDepth같은 속성을 지원합니다.

Visual Studio에서 새 Windows 앱 SDK 프로젝트를 만들 때 프로젝트 템플릿은 MainWindow 클래스( Microsoft.UI.Xaml.Window 형식))를 만듭니다. 그러나 프레임 또는 페이지 를 만들지 않고 탐색 코드도 제공하지 않습니다.

페이지 간 탐색을 활성화하려면 FrameMainWindow루트 요소로 추가합니다. 작업을 수행할 수 있는 Application.OnLaunched 메서드 재정의는 App.xaml 코드 숨김 파일에 있습니다. 이 App 코드 숨김 파일을 열고 OnLaunched 재정의를 업데이트하며, 여기에 표시된 대로 NavigationFailed 이벤트를 처리합니다.

// App.xaml.cs

protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    m_window = new MainWindow();

    // Create a Frame to act as the navigation context and navigate to the first page
    Frame rootFrame = new Frame();
    rootFrame.NavigationFailed += OnNavigationFailed;
    // Navigate to the first page, configuring the new page
    // by passing required information as a navigation parameter
    rootFrame.Navigate(typeof(MainPage), args.Arguments);

    // Place the frame in the current Window
    m_window.Content = rootFrame;
    // Ensure the MainWindow is active
    m_window.Activate();
}

void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
    throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
// App.xaml.h

// Add after OnLaunched declaration.
void OnNavigationFailed(IInspectable const&, Microsoft::UI::Xaml::Navigation::NavigationFailedEventArgs const&);

///////////////
// App.xaml.cpp

void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    window = make<MainWindow>();
    Frame rootFrame = Frame();
    rootFrame.NavigationFailed({ this, &App::OnNavigationFailed });
    rootFrame.Navigate(xaml_typename<BasicNavigation::MainPage>(), box_value(e.Arguments()));
    window.Content(rootFrame);
    window.Activate();
}

void App::OnNavigationFailed(IInspectable const&, NavigationFailedEventArgs const& e)
{
    throw hresult_error(E_FAIL, hstring(L"Failed to load Page ") + e.SourcePageType().Name);
}

참고 항목

탐색이 더 복잡한 앱의 경우, 일반적으로 NavigationView 를 MainWindow의 루트로 사용하고, Frame 를 탐색 뷰의 콘텐츠로 배치합니다. 자세한 정보는, 탐색 뷰를 참조하세요.

Navigate 메서드는 Frame 의 콘텐츠를 표시하는 데 사용됩니다. 여기서, MainPage.xamlNavigate 메서드에 전달되므로, 메서드는 MainPageFrame로 로드합니다.

앱의 초기 창 탐색에 실패하면, NavigationFailed 이벤트가 발생하고 이 코드는 이벤트 처리기에서 예외를 throw합니다.

3. 기본 페이지 추가

빈 앱 템플릿은 여러 앱 페이지를 만들지 않습니다. 페이지 간에 탐색하려면 앱에 일부 페이지를 추가해야 합니다.

앱에 새 항목을 추가하려면 다음을 수행합니다.

  1. 솔루션 탐색기에서, BasicNavigation 프로젝트 노드를 마우스 우클릭하여 컨텍스트 메뉴를 엽니다.
  2. 컨텍스트 메뉴에서 추가>새 항목 을 선택합니다.
  3. 새 항목 추가 대화 상자에서, 왼쪽 창에서 WinUI 노드를 선택한 후, 빈 페이지(WinUI 3) 를 가운데 창에서 선택합니다.
  4. 이름 상자에 입력하고 MainPage 누를 버튼은 추가 버튼입니다.
  5. 1-4단계를 반복하여 두 번째 페이지를 추가하지만 이름 상자에 Page2입력합니다.

이제, 이 파일은 BasicNavigation 프로젝트의 일부로 나열됩니다.

C# C++
  • MainPage.xaml
  • MainPage.xaml.cs
  • Page2.xaml
  • Page2.xaml.cs
  • MainPage.xaml
  • MainPage.xaml.cpp
  • MainPage.xaml.h
  • Page2.xaml
  • Page2.xaml.cpp
  • Page2.xaml.h

Important

C++ 프로젝트의 경우, 다른 페이지를 참조하는 각 페이지의 헤더 파일에 #include 지시문을 추가해야 합니다. 여기에 표시된 페이지 간 탐색 예제의 경우, mainpage.xaml.h 파일에는 #include "Page2.xaml.h"이 포함되는 반면, page2.xaml.h에는 #include "MainPage.xaml.h"이 포함됩니다.

C++ 페이지 템플릿에는 Button 예제를 포함하고 XAML 및 페이지의 코드 숨김 파일에서 제거해야 하는 클릭 처리기 코드도 포함됩니다.

페이지에 콘텐츠 추가

MainPage.xaml에서, 기존 페이지 콘텐츠를 다음 콘텐츠로 대체합니다.

<Grid>
    <TextBlock x:Name="pageTitle" Text="Main Page"
               Margin="16" Style="{StaticResource TitleTextBlockStyle}"/>
    <HyperlinkButton Content="Click to go to page 2"
                     Click="HyperlinkButton_Click"
                     HorizontalAlignment="Center"/>
</Grid>

이 XAML은 다음을 추가합니다.

  • TextBlock 요소의 이름은 pageTitleText 속성을 갖고 있는데, Main Page 루트 Grid의 자식 요소로 설정되어 있습니다.
  • HyperlinkButton 요소는 루트 Grid자식 요소로서 다음 페이지로 이동하는 데 사용됩니다.

MainPage 코드 숨김 파일에, 다음의 파일을 추가하세요. 이는 Click 이벤트가 위치한 HyperlinkButton 을 통해 Page2.xaml로의 탐색을 활성화하기 위함입니다.

// MainPage.xaml.cs

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    Frame.Navigate(typeof(Page2));
}
// pch.h
// Add this include in pch.h to support winrt::xaml_typename

#include <winrt/Windows.UI.Xaml.Interop.h>

////////////////////
// MainPage.xaml.h

void HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);

////////////////////
// MainPage.xaml.cpp

void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
    Frame().Navigate(winrt::xaml_typename<BasicNavigation::Page2>());
}

MainPagePage 클래스의 하위 클래스입니다. 이 Page 클래스는 읽기 전용 Frame 속성을 갖고 있으며, FramePage를 포함하고 있습니다. 만약 ClickHyperlinkButton 이벤트 호출기가 있는 MainPage 여기에서 해당 호출기로 Frame.Navigate(typeof(Page2))를 호출한다면, FramePage2.xaml해당 내용을 표시합니다.

페이지가 프레임에 로드될 때마다, 페이지는 PageStackEntry 로서 BackStack 또는 ForwardStack 에 추가되는데, 그 위치는 Frame입니다. 이를 통해 기록 및 뒤로 탐색을 사용할 수 있습니다.

이제, Page2.xaml에서 동일한 작업을 수행합니다. 기존 페이지의 콘텐츠를 다음 콘텐츠로 대체합니다.

<Grid>
    <TextBlock x:Name="pageTitle" Text="Page 2"
               Margin="16" Style="{StaticResource TitleTextBlockStyle}"/>
    <HyperlinkButton Content="Click to go to main page"
                     Click="HyperlinkButton_Click"
                     HorizontalAlignment="Center"/>
</Grid>

Page2 코드 숨김 파일에서, 다음의 파일을 추가하여 처리할 Click 이벤트의 위치는 HyperlinkButton 이며, 이는 MainPage.xaml를 탐색하기 위한 작업입니다.

// Page2.xaml.cs

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    Frame.Navigate(typeof(MainPage));
}
// Page2.xaml.h

void HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);

/////////////////
// Page2.xaml.cpp

void winrt::BasicNavigation::implementation::Page2::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
    Frame().Navigate(winrt::xaml_typename<BasicNavigation::MainPage>());
}

앱을 빌드하고 실행합니다. "2페이지로 이동하려면 클릭하세요"라는 링크를 클릭합니다. 맨 위에 있는 "페이지 2"가 표시된 두 번째 페이지를 로드하고 프레임에 표시해야 합니다. 이제 2페이지의 링크를 클릭하여 기본 페이지로 돌아갑니다.

4. 페이지 간에 정보 전달

이제 앱이 두 페이지 사이를 탐색하지만 아직 흥미로운 작업을 수행하지는 않습니다. 앱에 여러 페이지가 있는 경우 페이지에서 정보를 공유해야 하는 경우가 많습니다. 이제 첫 번째 페이지에서 두 번째 페이지로 일부 정보를 전달합니다.

MainPage.xaml에서, 이전에 추가한 HyperlinkButton 를 다음 StackPanel로 바꿉니다. 텍스트 문자열 입력을 위해 TextBlock 레이블 및 TextBoxname 을 추가합니다.

<StackPanel VerticalAlignment="Center">
    <TextBlock HorizontalAlignment="Center" Text="Enter your name"/>
    <TextBox HorizontalAlignment="Center" Width="200" x:Name="name"/>
    <HyperlinkButton Content="Click to go to page 2"
                              Click="HyperlinkButton_Click"
                              HorizontalAlignment="Center"/>
</StackPanel>

이제 Navigate 메서드의 두 번째 오버로드를 사용하고 두 번째 매개 변수로서 텍스트 상자의 텍스트를 전달합니다. 다음은 Navigate 오버로드의 시그니처입니다.

public bool Navigate(System.Type sourcePageType, object parameter);
bool Navigate(TypeName const& sourcePageType, IInspectable const& parameter);

HyperlinkButton_Click 이벤트 처리기가 있는 위치는 MainPage 코드 숨김 파일인데, 여기 있는 이벤트 처리기에서 두 번째 매개 변수를 더할 Navigate 메서드가 참조할 Text 속성의 위치는 name 텍스트 상자입니다.

// MainPage.xaml.cs

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    Frame.Navigate(typeof(Page2), name.Text);
}
// MainPage.xaml.cpp

void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{ 
    Frame().Navigate(xaml_typename<BasicNavigation::Page2>(), winrt::box_value(name().Text()));
}

Page2.xaml에서, 기존에 추가한 HyperlinkButton 를 다음 StackPanel으로 바꿉니다. 이것으로 추가할 TextBlock 의 목적은 MainPage에서 전달받은 텍스트 문자열을 표시하기 위함입니다.

<StackPanel VerticalAlignment="Center">
    <TextBlock HorizontalAlignment="Center" x:Name="greeting"/>
    <HyperlinkButton Content="Click to go to page 1"
                     Click="HyperlinkButton_Click"
                     HorizontalAlignment="Center"/>
</StackPanel>

Page2 코드 숨김 파일에, 다음의 코드를 추가해 OnNavigatedTo 메서드를 재정의합니다.

// Page2.xaml.cs

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if (e.Parameter is string && !string.IsNullOrWhiteSpace((string)e.Parameter))
    {
        greeting.Text = $"Hello, {e.Parameter.ToString()}";
    }
    else
    {
        greeting.Text = "Hello!";
    }
    base.OnNavigatedTo(e);
}
// Page2.xaml.h

void Page2::OnNavigatedTo(Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e)
{
	auto propertyValue{ e.Parameter().as<Windows::Foundation::IPropertyValue>() };
	if (propertyValue.Type() == Windows::Foundation::PropertyType::String)
	{
		auto name{ winrt::unbox_value<winrt::hstring>(e.Parameter()) };
		if (!name.empty())
		{
			greeting().Text(L"Hello, " + name);
			__super::OnNavigatedTo(e);
			return;
		}
	}
	greeting().Text(L"Hello!");
	__super::OnNavigatedTo(e);
}

앱을 실행하고 텍스트 상자에 이름을 입력한 다음 Click to go to page 2라는 링크를 클릭합니다.

만약 Click 이벤트의 HyperlinkButton 위치가 MainPage 인 상황에서 해당 이벤트가 Frame.Navigate(typeof(Page2), name.Text)를 호출하는 경우, name.Text 속성을 Page2로 전달한 후, 이벤트 데이터의 값을 페이지에 표시되는 메시지를 위해 사용합니다.

5. 페이지 캐시

페이지 콘텐츠 및 상태는 기본적으로 캐시되지 않으므로, 캐시 정보를 사용하고 싶다면 앱의 각 페이지에서 이를 사용하도록 설정해야 합니다.

기본 피어 투 피어 예제에서, Click to go to page 1 링크를 Page2에서 클릭하면, TextBox (및 다른 필드)가 MainPage 에서 기본 상태로 설정됩니다. 이 작업을 해결하는 방법으로 NavigationCacheMode 속성을 사용하여 프레임의 페이지 캐시에 페이지를 추가하도록 지정하는 것이 있습니다.

기본적으로 탐색이 발생할 때마다 기본값을 사용하여 새 페이지 인스턴스가 만들어집니다. 이 MainPage.xaml에서, NavigationCacheModeEnabled 로 설정하여 (여는 Page 태그에서) 프레임용 페이지 캐시가 초과될 때까지 페이지를 위한 모든 콘텐츠 및 상태 값을 유지하고 페이지를 캐시합니다. NavigationCacheModeRequired로 설정하면, 프레임에서 캐시 저장되는 탐색 기록의 페이지 수를 지정하는 CacheSize 제한을 무시할 수 있습니다. 그러나 캐시 크기 제한은 디바이스의 메모리 제한에 따라 중요할 수 있습니다.

<Page
    x:Class="BasicNavigation.MainPage"
    ...
    mc:Ignorable="d"
    NavigationCacheMode="Enabled">

이제 기본 페이지로 돌아가면 입력란에 입력한 이름이 그대로 유지됩니다.

6. 페이지 전환 애니메이션 사용자 지정

기본적으로 탐색이 발생할 때 프레임의 각 페이지에 애니메이션 효과가 생깁니다. 기본 애니메이션은 페이지가 창의 아래쪽에서 위로 미끄러지도록 하는 "입장" 애니메이션입니다. 그러나 앱 탐색에 더 적합한 다양한 애니메이션 옵션을 선택할 수 있습니다. 예를 들어, "드릴 인" 애니메이션을 사용하여 사용자가 앱에 더 깊이 들어가고 있다는 느낌을 주거나 가로 슬라이드 애니메이션을 사용하여 두 페이지가 피어라는 느낌을 줄 수 있습니다. 자세한 내용은 페이지 전환을 참조하세요.

이러한 애니메이션은 NavigationTransitionInfo의 하위 클래스로 표시됩니다. 페이지 전환에 사용할 애니메이션을 지정하려면 Navigate 메서드의 세 번째 오버로드를 사용하고 NavigationTransitionInfo 하위 클래스를 세 번째 매개 변수(infoOverride)로 전달합니다. 다음은 Navigate 오버로드의 시그니처입니다.

public bool Navigate(System.Type sourcePageType, 
                     object parameter,
                     NavigationTransitionInfo infoOverride);
bool Navigate(TypeName const& sourcePageType, 
              IInspectable const& parameter, 
              NavigationTransitionInfo const& infoOverride);

HyperlinkButton_Click 이벤트 처리기가 MainPage 코드 숨김 파일에 위치해 잇는데, 해당 이벤트 처리기가 세 번째 매개 변수를 추가하는 Navigate 메서드에서 infoOverride 매개 변수를 SlideNavigationTransitionInfo 로 설정합니다. 또한 SlideNavigationTransitionInfo는 Effect 속성이 FromRight으로 설정되어 있습니다.

// MainPage.xaml.cs

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    Frame.Navigate(typeof(Page2), 
                   name.Text,
                   new SlideNavigationTransitionInfo() 
                       { Effect = SlideNavigationTransitionEffect.FromRight});
}
// pch.h

#include <winrt/Microsoft.UI.Xaml.Media.Animation.h>

////////////////////
// MainPage.xaml.cpp

using namespace winrt::Microsoft::UI::Xaml::Media::Animation;

// ...

void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{   
    // Create the slide transition and set the transition effect to FromRight.
    SlideNavigationTransitionInfo slideEffect = SlideNavigationTransitionInfo();
    slideEffect.Effect(SlideNavigationTransitionEffect(SlideNavigationTransitionEffect::FromRight));
    Frame().Navigate(winrt::xaml_typename<BasicNavigation::Page2>(),
        		     winrt::box_value(name().Text()),
                     slideEffect);
}

HyperlinkButton_Click 이벤트 처리기가 Page2 코드 숨김 파일에 위치해 있는데, 해당 이벤트 처리기가 infoOverride 매개 변수를 SlideNavigationTransitionInfo 에 설정합니다. 해당 SlideNavigationTransitionInfo에는 Effect 속성이 FromLeft로 설정되어 있습니다.

// Page2.xaml.cs

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    Frame.Navigate(typeof(MainPage),
                   null,
                   new SlideNavigationTransitionInfo() 
                       { Effect = SlideNavigationTransitionEffect.FromLeft});
}
// Page2.xaml.cpp

using namespace winrt::Microsoft::UI::Xaml::Media::Animation;

// ...

void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{   
    // Create the slide transition and set the transition effect to FromLeft.
    SlideNavigationTransitionInfo slideEffect = SlideNavigationTransitionInfo();
    slideEffect.Effect(SlideNavigationTransitionEffect(SlideNavigationTransitionEffect::FromLeft));
    Frame().Navigate(winrt::xaml_typename<BasicNavigation::MainPage>(),
        		     nullptr,
                     slideEffect);
}

이제 페이지 사이를 탐색할 때 페이지가 좌우로 슬라이드로 이동하므로, 자연스럽게 전환한다는 느낌을 제공하고 페이지 간의 연결을 강화합니다.