티스토리 뷰
Page navigation part2
지난번 소스에서 많은 부분을 수정해서 실제 프로젝트에서 사용이 가능할 정도까지 만들었고, 소스는 모두 ReSharper를 이용해서 정리했다. 또한, 이 소스를 이용해서 개발을 시작 할 수 있도록 좀 자세하게 설명을 추가 하니 좀 길더라도 이해하기 바란다.
0. 환경
Visual Studio 2013 Update 2
Windows 8.1
지난번 사용한 UniversalSample 소스 - 참고 정도?
1. 기본
프로젝트는 UniversalSample.Windows(Windows 8.1 store app), UniversalSample.WindowsPhone(Windows Phone 8.1 app), UniversalSample.Shared 3개의 프로젝트로 구성된다.
1-1. UniversalSample.Shared
W8.1과 WP8.1 프로젝트에서 공통으로 사용되는 대부분의 코드가 이 프로젝트에 위치하고 있다.
. Commons folder
- BindableBase.cs : 바인딩 클래스
- FrameHelper.cs : 프레임 헬퍼 클래스, 네비게이션을 담당한다.
- RelayCommand.cs : 커맨드 클래스(ICommand를 상속받은 커맨드 생성용 클래스)
- SuspensionManager.cs : 서스팬션 메니저로 앱이 서스팬드 모드로 돌입하거나 나올때 필요한 데이터를 저장하고 복구시킨다.
- ViewModelBase.cs : 뷰모델 베이스 클래스
. Design folder : 디자인 데이터 폴더
. Models folder : 모델 폴더
. ViewModels folder : 뷰모델 폴더
App.xaml : 앱 시작시에 필요한 내용이 들어있음
1-2. UniversalSample.Windows
. Assets folder : 이미지 리소스가 포함되어 있다.
. Views : 뷰 폴더
1-3. UniversalSample.WindowsPhone
. Assets folder : 이미지 리소스가 포함되어 있다.
. Views : 뷰 폴더
* 주의할 사항은 Windows프로젝트와 WindowsPhone 프로젝트는 모두 동일한 폴더 구조와 동일한 뷰 이름을 가져야 한다.
2. App.xaml과 App.xaml.cs를 살펴 본다.
앱이 시작될 때 어떤 동작들이 실행되는지 살펴 보도록 하자.
App.xaml
<Application
x:Class="UniversalSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="using:UniversalSample.ViewModels">
<Application.Resources>
<x:String x:Key="AppName">Universal Sample</x:String>
<viewModel:ViewModelLocator x:Key="Locator" />
</Application.Resources>
</Application>
앱이 시작 될 때 앱 전체에서 사용할 리소스를 이곳에 정의한다.
AppName이라는 문자열 리소스를 하나 만들고, ViewModelLocator라는 클래스를 생성해서 리소스로 사용한다.
뷰모델로케이터는 두가지 용도로 사용되는데, 하나는 앱 전체에서 하나의 뷰모델만 유지 하기 위함이고, 또 하나는 템플릿 내부에서 뷰모델에 있는 내용을 바인딩(주로 커맨드)할 때 사용한다.
App.xaml.cs
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
DebugSettings.EnableFrameRateCounter = true;
}
#endif
var rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame {CacheSize = 1};
// TODO: change this value to a cache size that is appropriate for your application
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
// TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
// 루트 프레임을 FrameHelper에 등록한다.
FrameHelper.Instance.RegisterFrame(rootFrame);
}
//루트 프레임의 컨텐츠가 null이면 MainPage로 네비게이션한다.
if (rootFrame.Content == null)
{
#if WINDOWS_PHONE_APP
// Removes the turnstile navigation for startup.
if (rootFrame.ContentTransitions != null)
{
this.transitions = new TransitionCollection();
foreach (var c in rootFrame.ContentTransitions)
{
this.transitions.Add(c);
}
}
rootFrame.ContentTransitions = null;
rootFrame.Navigated += this.RootFrame_FirstNavigated;
#endif
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!FrameHelper.Instance.Navigation(typeof(MainPage), e.Arguments))
{
throw new Exception("Failed to create initial page");
}
}
// Ensure the current window is active
Window.Current.Activate();
}
* 기존 유니버셜앱 템플릿에 있는 NavigationHelper는 MVVM 패턴에서는 사용하기가 좀 그렇다, 그래서 ViewModel에서 네비게이션 관련 처리를 모두 할 수 있도록 수정한 것이 이 셈플이다.
위에서 앱이 시작되면 MainPage로 네비게이션을 시키도록 되어있다. 이제 MainPage.xaml.cs를 보도록 하자.
3. MainPage.xaml.cs
using Windows.ApplicationModel;
using Windows.UI.Xaml.Controls;
using UniversalSample.ViewModels;
namespace UniversalSample.Views
{
public sealed partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
if (DesignMode.DesignModeEnabled == false)
{
var locator = App.Current.Resources["Locator"] as ViewModelLocator;
if (locator != null) DataContext = DataContext ?? locator.MainPageVM;
}
}
}
}
간단하게 코딩 했다. 런타임이라면 앱의 리소스에서 ViewModelLocator를 찾고, 뷰모델로케이터에 있는 MainPageVM을 가지고 와서 DataContext에 넣어 준다. 그렇다면 ViewModelLocator는 어떤 내용이 있는지 보아야 할 때다.
4. ViewModelLocator.cs
namespace UniversalSample.ViewModels
{
public class ViewModelLocator
{
private ClassDetailPageVM _classDetailPageVM;
private MainPageVM _mainPageVM;
public MainPageVM MainPageVM
{
get { return _mainPageVM = _mainPageVM ?? new MainPageVM(); }
}
public ClassDetailPageVM ClassDetailPageVM
{
get { return _classDetailPageVM = _classDetailPageVM ?? new ClassDetailPageVM(); }
}
}
}
ViewModelLocator는 2개의 뷰모델을 프로퍼티로 가지고 있으며, 각 프로퍼티가 사용이 되는 시점에 인스턴스가 되도록 되어 있다. 아주 특별한 내용은 없다. 그러면, MainPageVM.cs의 내용을 살펴보자
5. MainPageVM.cs
using System.Collections.Generic;
using Windows.ApplicationModel;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
using UniversalSample.Commons;
using UniversalSample.Design;
using UniversalSample.Models;
using UniversalSample.Views;
namespace UniversalSample.ViewModels
{
/// <summary>
/// MainPage ViewModel
/// </summary>
public class MainPageVM : ViewModelBase
{
private IList<ClassM> _classList;
private RelayCommand _itemClickCommand;
private IList<PersonM> _people;
/// <summary>
/// Constructor
/// </summary>
public MainPageVM()
{
Title = "Kaki education center";
ClassList = new List<ClassM>();
People = new List<PersonM>();
if (DesignMode.DesignModeEnabled)
{
//디자인 타임 데이터
ClassList = DesignDatas.GetClassList();
People = DesignDatas.GetPeople();
}
}
/// <summary>
/// Class List
/// </summary>
public IList<ClassM> ClassList
{
get { return _classList; }
set
{
_classList = value;
OnPropertyChanged();
}
}
/// <summary>
/// People
/// </summary>
public IList<PersonM> People
{
get { return _people; }
set
{
_people = value;
OnPropertyChanged();
}
}
/// <summary>
/// ItemClick Command
/// </summary>
public RelayCommand ItemClickCommand
{
get
{
return _itemClickCommand = _itemClickCommand ?? new RelayCommand(
args =>
{
if (!(args is ItemClickEventArgs)) return;
var item = ((ItemClickEventArgs) args).ClickedItem as ClassM;
if (item == null) return;
FrameHelper.Instance.Navigation(typeof (ClassDetailPage), item);
});
}
}
/// <summary>
/// OnNavigated
/// </summary>
/// <param name="e"></param>
protected override void OnNavigated(NavigationEventArgs e)
{
//네비게이션이 완료 된 후 실행되는 부분, 지금은 디자인 타임과 동일한 데이터를 보여준다.
ClassList = DesignDatas.GetClassList();
People = DesignDatas.GetPeople();
}
}
}
public RelayCommand ItemClickCommand
커맨드 프로퍼티로 ListView의 ItemClick이벤트를 처리하며, args에는 ItemClick 이벤트의 아규먼트인 ItemClickEventArgs가 반환되는데, 이 것은 InvokeCommandAction에서 CommandParameter를 지정하지 않으면 반환되는 것이다.
FrameHelper.Instance.Navigation(typeof (ClassDetailPage), item);
ClassDetailPage로 item object를 가지고 네비게이션 한다. 네비게이션 파라메터는 기본적으로는 string을 넘기도록 하지만, object를 넘겨도 큰 문제는 없다. 대신 네비게이션 파라메터를 serialization해서 저장을 하는 것은 할 수 없다. 만약 그렇게 해야만 한다면, string만을 넘기도록 한다.
protected override void OnNavigated(NavigationEventArgs e)
MainPage가 Navigated가 된후 실행되는 가상 메소드이다. 네비게이션과 관련된 가상 메소드들은 ViewModelBase.cs에 선언되어 있다. 네비게이션 과정이 어떻체 처리되는지 더 자세하게 알려면, FrameHelper.cs와 ViewModelBase.cs를 자세히 보면 된다.
6. MainPage.xaml - Windows 8.1
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:ViewModels="using:UniversalSample.ViewModels"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
x:Class="UniversalSample.Views.MainPage"
mc:Ignorable="d">
<Page.Resources>
<!--ListViewItem의 가로 너비를 Stretch하도록 한다-->
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</Page.Resources>
<!--디자인타임 뷰모델, Blend를 이용해서 작업하면 이렇게 저장된다. Visual Studio에서는 <d:Page.DataContext>로 사용하면 된다. -->
<d:DataContext>
<ViewModels:MainPageVM />
</d:DataContext>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition />
</TransitionCollection>
</Grid.ChildrenTransitions>
<Hub>
<Hub.Header>
<!-- Back button and page title -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!--GoBackCommand로 변경, ViewModelBase에 있는 커맨드-->
<Button Margin="-1,-1,39,0"
Command="{Binding GoBackCommand, Mode=OneWay}"
Style="{StaticResource NavigationBackButtonNormalStyle}"
VerticalAlignment="Top"
AutomationProperties.Name="Back"
AutomationProperties.AutomationId="BackButton"
AutomationProperties.ItemType="Navigation Button" />
<!--App.xaml에서 추가해 놓았던 AppName을 여기서 사용-->
<TextBlock
Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1"
IsHitTestVisible="false" TextWrapping="NoWrap" VerticalAlignment="Top"
Text="{StaticResource AppName}" />
</Grid>
</Hub.Header>
<!--앱에서 사용하던 이미지를 셈플로 사용-->
<HubSection Width="500" Margin="0,0,80,0">
<HubSection.Background>
<ImageBrush Stretch="UniformToFill" ImageSource="ms-appx:///Assets/storelogo558_756.png" />
</HubSection.Background>
</HubSection>
<!--클래스 목록-->
<HubSection Header="Class List" MinWidth="400" HorizontalContentAlignment="Stretch">
<DataTemplate>
<Grid>
<!--ItemClick이벤트를 사용하기 위해서는 IsItemClickEnabled가 True여야 한다-->
<ListView ItemsSource="{Binding ClassList}" HorizontalContentAlignment="Stretch"
SelectionMode="None" IsItemClickEnabled="True">
<!--리스트뷰에 헤더 템플릿을 이용-->
<ListView.HeaderTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.4*" />
<ColumnDefinition Width="0.6*" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width="15" />
</Grid.ColumnDefinitions>
<TextBlock Style="{StaticResource BodyTextBlockStyle}">
<Run Text="Name" />
</TextBlock>
<TextBlock Grid.Column="1" Style="{StaticResource BodyTextBlockStyle}">
<Run Text="Description" />
</TextBlock>
<TextBlock Grid.Column="2" Style="{StaticResource BodyTextBlockStyle}">
<Run Text="Count" />
</TextBlock>
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<!--아이템 템플릿-->
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.4*" />
<ColumnDefinition Width="0.6*" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Style="{StaticResource BodyTextBlockStyle}"
Margin="0,0,4,0" />
<TextBlock Grid.Column="1" Text="{Binding Description}"
Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Grid.Column="2" Text="{Binding People.Count, Mode=OneWay}"
Style="{StaticResource BodyTextBlockStyle}"
HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<!--인터렉티비티-->
<Interactivity:Interaction.Behaviors>
<!--아이템클릭이벤트에 반응-->
<Core:EventTriggerBehavior EventName="ItemClick">
<!--ItemClickCommand를 실행시키는데 CommandParameter는 ItemClickEventArgs가 자동으로 입력된다.-->
<Core:InvokeCommandAction Command="{Binding ItemClickCommand, Mode=OneWay}" />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</ListView>
</Grid>
</DataTemplate>
</HubSection>
<!--People 프로퍼티 내용 출력용으로 중요한 부분은 없다-->
<HubSection MinWidth="400" Header="People" HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch">
<DataTemplate>
<Grid>
<ListView ItemsSource="{Binding People}" HorizontalContentAlignment="Stretch"
SelectionMode="None">
<ListView.HeaderTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="15" />
</Grid.ColumnDefinitions>
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Text="Name" />
<TextBlock Grid.Column="1" Style="{StaticResource BodyTextBlockStyle}"
Text="Age" />
<TextBlock Grid.Column="2" Style="{StaticResource BodyTextBlockStyle}"
Text="Sex" />
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Style="{StaticResource BodyTextBlockStyle}"
Margin="0,0,4,0" />
<TextBlock Grid.Column="1" Text="{Binding Age}"
Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Grid.Column="2" Text="{Binding Sex}"
Style="{StaticResource BodyTextBlockStyle}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</HubSection>
</Hub>
</Grid>
</Page>
7. MainPage.xaml - Windows Phone 8.1
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:ViewModels="using:UniversalSample.ViewModels"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
x:Class="UniversalSample.Views.MainPage"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<!--ListViewItem의 가로 너비를 Stretch하도록 한다-->
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</Page.Resources>
<!--디자인타임 뷰모델, Blend를 이용해서 작업하면 이렇게 저장된다.-->
<d:DataContext>
<ViewModels:MainPageVM />
</d:DataContext>
<Grid>
<!--App.xaml에서 추가해 놓았던 AppName을 여기서 사용-->
<Hub Header="{StaticResource AppName}">
<!--앱에서 사용하던 이미지를 셈플로 사용, 이미지는 Windows 8.1 프로젝트에 있는 이미지의 링크이미지임-->
<HubSection>
<HubSection.Background>
<ImageBrush Stretch="UniformToFill" ImageSource="ms-appx:///Assets/storelogo558_756.png" />
</HubSection.Background>
</HubSection>
<!--클래스 목록, 너비를 지정하지 않는다-->
<HubSection Header="Class List">
<DataTemplate>
<Grid>
<!--ItemClick이벤트를 사용하기 위해서는 IsItemClickEnabled가 True여야 한다-->
<ListView ItemsSource="{Binding ClassList}" HorizontalContentAlignment="Stretch"
SelectionMode="None" IsItemClickEnabled="True">
<!--리스트뷰에 헤더 템플릿을 이용-->
<ListView.HeaderTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.4*" />
<ColumnDefinition Width="0.6*" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<TextBlock Style="{StaticResource BodyTextBlockStyle}">
<Run Text="Name" />
</TextBlock>
<TextBlock Grid.Column="1" Style="{StaticResource BodyTextBlockStyle}">
<Run Text="Description" />
</TextBlock>
<TextBlock Grid.Column="2" Style="{StaticResource BodyTextBlockStyle}">
<Run Text="Count" />
</TextBlock>
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<!--아이템 템플릿-->
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.4*" />
<ColumnDefinition Width="0.6*" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Style="{StaticResource BodyTextBlockStyle}"
Margin="0,0,4,0" />
<TextBlock Grid.Column="1" Text="{Binding Description}"
Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Grid.Column="2" Text="{Binding People.Count, Mode=OneWay}"
Style="{StaticResource BodyTextBlockStyle}"
HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<!--인터렉티비티-->
<Interactivity:Interaction.Behaviors>
<!--아이템클릭이벤트에 반응-->
<Core:EventTriggerBehavior EventName="ItemClick">
<!--ItemClickCommand를 실행시키는데 CommandParameter는 ItemClickEventArgs가 자동으로 입력된다.-->
<Core:InvokeCommandAction Command="{Binding ItemClickCommand, Mode=OneWay}" />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</ListView>
</Grid>
</DataTemplate>
</HubSection>
<!--People 프로퍼티 내용 출력용으로 중요한 부분은 없다-->
<HubSection Header="People">
<DataTemplate>
<Grid>
<ListView ItemsSource="{Binding People}" HorizontalContentAlignment="Stretch"
SelectionMode="None">
<ListView.HeaderTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Text="Name" />
<TextBlock Grid.Column="1" Style="{StaticResource BodyTextBlockStyle}"
Text="Age" />
<TextBlock Grid.Column="2" Style="{StaticResource BodyTextBlockStyle}"
Text="Sex" />
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Style="{StaticResource BodyTextBlockStyle}"
Margin="0,0,4,0" />
<TextBlock Grid.Column="1" Text="{Binding Age}"
Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Grid.Column="2" Text="{Binding Sex}"
Style="{StaticResource BodyTextBlockStyle}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</HubSection>
</Hub>
</Grid>
</Page>
* 6번 MainPage.xaml과 7번 MainPage.xaml은 작은 차이가 몇가지가 있다. 우선은 헤더 부분이 다르고, 허브 Section에 너비를 지정하지 않아야 하고, ItemTemplate이 약간 다르다. 이런 작은 차이가 있기 때문에 하나의 xaml을 두 프로젝트에서 공통으로 사용하기에는 문제가 있을 것 같아 그냥 2개로 분리하는 방향으로 했다. 이 방법말고 VisualState를 이용하는 방법도 있기는 한데 파일은 하나지만 관리하기가 더 어렵지 않을까 생각된다.
이제 두번째 페이지를 살펴보자
8. ClassDetailPageVM.cs
using System.Linq;
using Windows.ApplicationModel;
using Windows.UI.Xaml.Navigation;
using UniversalSample.Commons;
using UniversalSample.Design;
using UniversalSample.Models;
namespace UniversalSample.ViewModels
{
/// <summary>
/// ClassDetailPage ViewModel
/// </summary>
public class ClassDetailPageVM : ViewModelBase
{
private ClassM _currentClass;
/// <summary>
/// Constructor
/// </summary>
public ClassDetailPageVM()
{
Title = "Class detail page";
if (DesignMode.DesignModeEnabled)
{
//디자인 타임에서는 첫번째 데이터를 이용한다.
CurrentClass = DesignDatas.GetClassList().First();
}
}
/// <summary>
/// Current Class
/// </summary>
public ClassM CurrentClass
{
get { return _currentClass; }
set
{
_currentClass = value;
OnPropertyChanged();
}
}
/// <summary>
/// Navigating
/// </summary>
/// <param name="e"></param>
protected override void OnNavigating(NavigatingCancelEventArgs e)
{
CurrentClass = null;
}
/// <summary>
/// Navigated
/// </summary>
/// <param name="e"></param>
protected override void OnNavigated(NavigationEventArgs e)
{
if (e.NavigationMode == NavigationMode.New)
{
CurrentClass = e.Parameter as ClassM;
}
}
}
}
protected override void OnNavigated(NavigationEventArgs e)
네비게이션이 완료된 후 호출되는 가상 메소드로 NavigationMode가 New인 경우에 CurrentClass에 네비게이션 파라메터를 입력한다.
protected override void OnNavigating(NavigatingCancelEventArgs e)
네비게이션이 발생하기 전에 호출되는 가상 메소드로(여기서는 GoBack) CurrentClass = null을 실행한다. 특별히 네비게이션이 되기전에 처리할 내용이 있으면 이곳에서 처리하면 된다. 위의 내용은 예로 넣어 놓은 것 뿐이다.
뷰를 살펴보자.
9. ClassDetailPage.xaml - Windows 8.1
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:ViewModels="using:UniversalSample.ViewModels"
x:Class="UniversalSample.Views.ClassDetailPage"
mc:Ignorable="d">
<Page.Resources>
<!--디자인 리소스들-->
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
<Style x:Key="HeadBorderStyle" TargetType="Border">
<Setter Property="Background" Value="Gray" />
<Setter Property="BorderBrush" Value="White" />
<Setter Property="BorderThickness" Value="2" />
</Style>
<Style x:Key="DetailBorderStyle" TargetType="Border">
<Setter Property="BorderBrush" Value="DarkGray" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="Padding" Value="10" />
</Style>
</Page.Resources>
<!--디자인타임 뷰모델-->
<d:Page.DataContext>
<ViewModels:ClassDetailPageVM />
</d:Page.DataContext>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<!--에니메이션 효과-->
<Grid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition />
</TransitionCollection>
</Grid.ChildrenTransitions>
<Grid.RowDefinitions>
<RowDefinition Height="140" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="1" Margin="120,0,120,90">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="193*" />
<ColumnDefinition Width="490*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="31*" />
<RowDefinition Height="126*" />
</Grid.RowDefinitions>
<Border Style="{StaticResource HeadBorderStyle}">
<TextBlock Text="Name" Style="{StaticResource TitleTextBlockStyle}" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<Border Grid.Row="1" Grid.Column="0" Style="{StaticResource HeadBorderStyle}">
<TextBlock Text="Description" Style="{StaticResource TitleTextBlockStyle}"
VerticalAlignment="Center" HorizontalAlignment="Center" />
</Border>
<!--CurrentClass.Name 프로퍼티 바인딩-->
<Border Grid.Row="0" Grid.Column="1" Style="{StaticResource DetailBorderStyle}">
<TextBlock Text="{Binding CurrentClass.Name}" Style="{StaticResource BodyTextBlockStyle}"
VerticalAlignment="Center" />
</Border>
<!--CurrentClass.Description 프로퍼티 바인딩-->
<Border Grid.Row="1" Grid.Column="1" Style="{StaticResource DetailBorderStyle}">
<TextBlock Text="{Binding CurrentClass.Description}" Style="{StaticResource BodyTextBlockStyle}"
VerticalAlignment="Center" />
</Border>
</Grid>
<!--CurrentClass.People 프로퍼티 바인딩 HeaderTemplate, ItemTemplate는 MainPage에 있는 내용과 동일하다-->
<ListView Grid.Column="1" ItemsSource="{Binding CurrentClass.People}" HorizontalContentAlignment="Stretch"
BorderBrush="White" BorderThickness="2" Margin="20,0,0,0">
<ListView.HeaderTemplate>
<DataTemplate>
<Grid Height="40">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="15" />
</Grid.ColumnDefinitions>
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Text="Name" />
<TextBlock Grid.Column="1" Style="{StaticResource BodyTextBlockStyle}" Text="Age" />
<TextBlock Grid.Column="2" Style="{StaticResource BodyTextBlockStyle}" Text="Sex" />
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Style="{StaticResource BodyTextBlockStyle}"
Margin="0,0,4,0" />
<TextBlock Grid.Column="1" Text="{Binding Age}" Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Grid.Column="2" Text="{Binding Sex}" Style="{StaticResource BodyTextBlockStyle}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
<!-- Back button and page title -->
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!--GoBackCommand로 변경, ViewModelBase에 있는 커맨드-->
<Button Margin="39,59,39,0"
Command="{Binding GoBackCommand, Mode=OneWay}"
Style="{StaticResource NavigationBackButtonNormalStyle}"
VerticalAlignment="Top"
AutomationProperties.Name="Back"
AutomationProperties.AutomationId="BackButton"
AutomationProperties.ItemType="Navigation Button" />
<TextBlock Text="{Binding Title}" Style="{StaticResource HeaderTextBlockStyle}"
Grid.Column="1"
IsHitTestVisible="false" TextWrapping="NoWrap" VerticalAlignment="Bottom" Margin="0,0,30,40" />
</Grid>
</Grid>
</Page>
10. ClassDetailPage.xaml - Windows Phone 8.1
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:ViewModels="using:UniversalSample.ViewModels"
x:Class="UniversalSample.Views.ClassDetailPage"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Transitions>
<TransitionCollection>
<NavigationThemeTransition>
<ContinuumNavigationTransitionInfo />
</NavigationThemeTransition>
</TransitionCollection>
</Page.Transitions>
<Page.Resources>
<!--디자인 리소스들-->
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
<Style x:Key="HeadBorderStyle" TargetType="Border">
<Setter Property="Background" Value="Gray" />
<Setter Property="BorderBrush" Value="White" />
<Setter Property="BorderThickness" Value="2" />
</Style>
<Style x:Key="DetailBorderStyle" TargetType="Border">
<Setter Property="BorderBrush" Value="DarkGray" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="Padding" Value="10" />
</Style>
</Page.Resources>
<!--디자인타임 뷰모델-->
<d:Page.DataContext>
<ViewModels:ClassDetailPageVM />
</d:Page.DataContext>
<Grid>
<!--에니메이션 효과-->
<Grid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition />
</TransitionCollection>
</Grid.ChildrenTransitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- TitlePanel -->
<StackPanel Grid.Row="0" Margin="24,17,0,28">
<TextBlock x:Uid="Header" Text="{StaticResource AppName}" Style="{ThemeResource TitleTextBlockStyle}"
Typography.Capitals="SmallCaps" />
<TextBlock Text="{Binding Title}" Margin="0,12,0,0" Style="{ThemeResource HeaderTextBlockStyle}" />
</StackPanel>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="193*" />
<ColumnDefinition Width="490*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Style="{StaticResource HeadBorderStyle}">
<TextBlock Text="Name" Style="{StaticResource TitleTextBlockStyle}" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<Border Grid.Row="1" Grid.Column="0" Style="{StaticResource HeadBorderStyle}">
<TextBlock Text="Description" Style="{StaticResource TitleTextBlockStyle}"
VerticalAlignment="Center" HorizontalAlignment="Center" />
</Border>
<!--CurrentClass.Name 프로퍼티 바인딩-->
<Border Grid.Row="0" Grid.Column="1" Style="{StaticResource DetailBorderStyle}">
<TextBlock Text="{Binding CurrentClass.Name}" Style="{StaticResource BodyTextBlockStyle}"
VerticalAlignment="Center" />
</Border>
<!--CurrentClass.Description 프로퍼티 바인딩-->
<Border Grid.Row="1" Grid.Column="1" Style="{StaticResource DetailBorderStyle}">
<TextBlock Text="{Binding CurrentClass.Description}" Style="{StaticResource BodyTextBlockStyle}"
VerticalAlignment="Center" />
</Border>
</Grid>
<!--CurrentClass.People 프로퍼티 바인딩 HeaderTemplate, ItemTemplate는 MainPage에 있는 내용과 동일하다-->
<ListView Grid.Row="1" ItemsSource="{Binding CurrentClass.People}" HorizontalContentAlignment="Stretch"
BorderBrush="White" BorderThickness="2" Margin="0,10,0,0">
<ListView.HeaderTemplate>
<DataTemplate>
<Grid Height="40">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<TextBlock Style="{StaticResource BodyTextBlockStyle}" Text="Name" />
<TextBlock Grid.Column="1" Style="{StaticResource BodyTextBlockStyle}" Text="Age" />
<TextBlock Grid.Column="2" Style="{StaticResource BodyTextBlockStyle}" Text="Sex" />
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Style="{StaticResource BodyTextBlockStyle}"
Margin="0,0,4,0" />
<TextBlock Grid.Column="1" Text="{Binding Age}" Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Grid.Column="2" Text="{Binding Sex}" Style="{StaticResource BodyTextBlockStyle}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid>
</Page>
9번과 10번도 몇개의 차이점이 있는데, 우선 타이틀 부분이 버튼의 존재 여부 때문에 다르고, 컨텐츠의 배치를 윈폰은 세로로 만들었다.
이렇게 기본 셈플을 살펴보았다. 전체 소스를 받아서 살펴보면 더 쉽게 차이점을 알 수 있을 것이다.
전체 소스
'UWP & Windows App > Beginner' 카테고리의 다른 글
bitly서비스를 이용해서 url 짧게 변환 해보자 (0) | 2014.07.30 |
---|---|
Common PickSingleFileAsync - Universal (0) | 2014.06.18 |
Page navigation part1 (0) | 2014.05.19 |
Hello World Universal App (0) | 2014.05.10 |
Building Apps for Windows Phone 8.1 & Universal Apps (0) | 2014.05.06 |
- Total
- Today
- Yesterday
- #prism
- XAML
- #Windows Template Studio
- .net 5.0
- uno-platform
- ef core
- UWP
- Microsoft
- Visual Studio 2022
- ComboBox
- kiosk
- Always Encrypted
- MVVM
- Build 2016
- PRISM
- #uwp
- dotNETconf
- Behavior
- uno platform
- Windows 10
- windows 11
- C#
- IOT
- .net
- LINQ
- Cross-platform
- Bot Framework
- visual studio 2019
- WPF
- #MVVM
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |