■ ConnectedAnimation 클래스에서 페이지 이동시 애니메이션을 사용하는 방법을 보여준다.
▶ Person.cs
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
using System.ComponentModel; using System.Runtime.CompilerServices; using Windows.UI.Xaml.Media; namespace TestProject { /// <summary> /// 사람 /// </summary> public class Person : INotifyPropertyChanged { //////////////////////////////////////////////////////////////////////////////////////////////////// Event ////////////////////////////////////////////////////////////////////////////////////////// Public #region 속성 변경시 이벤트 - PropertyChanged /// <summary> /// 속성 변경시 이벤트 /// </summary> public event PropertyChangedEventHandler PropertyChanged; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// ID /// </summary> public int id; /// <summary> /// 성명 /// </summary> public string name; /// <summary> /// 나이 /// </summary> public int age; /// <summary> /// 브러시 /// </summary> public Brush brush; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region ID - ID /// <summary> /// ID /// </summary> public int ID { get => this.id; set { if(this.id != value) { this.id = value; FirePropertyChangedEvent(); } } } #endregion #region 성명 - Name /// <summary> /// 성명 /// </summary> public string Name { get => this.name; set { if(this.name != value) { this.name = value; FirePropertyChangedEvent(); } } } #endregion #region 나이 - Age /// <summary> /// 나이 /// </summary> public int Age { get => this.age; set { if(this.age != value) { this.age = value; FirePropertyChangedEvent(); } } } #endregion #region 브러시 - Brush /// <summary> /// 브러시 /// </summary> public Brush Brush { get => this.brush; set { if(this.brush != value) { this.brush = value; FirePropertyChangedEvent(); } } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - Person(id, name, age, brush) /// <summary> /// 생성자 /// </summary> /// <param name="id">ID</param> /// <param name="name">성명</param> /// <param name="age">나이</param> /// <param name="brush">브러시</param> public Person(int id, string name, int age, Brush brush) { this.id = id; this.name = name; this.age = age; this.brush = brush; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 속성 변경시 이벤트 발생시키기 - FirePropertyChangedEvent(propertyName) /// <summary> /// 속성 변경시 이벤트 발생시키기 /// </summary> /// <param name="propertyName">속성명</param> protected void FirePropertyChangedEvent([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); #endregion } } |
▶ App.xaml
1 2 3 4 5 6 |
<Application x:Class="TestProject.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> </Application> |
▶ App.xaml.cs
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
using System; using Windows.ApplicationModel; using Windows.ApplicationModel.Activation; using Windows.Foundation; using Windows.Graphics.Display; using Windows.UI.Core; using Windows.UI.ViewManagement; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace TestProject { /// <summary> /// 앱 /// </summary> sealed partial class App : Application { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - App() /// <summary> /// 생성자 /// </summary> public App() { InitializeComponent(); Suspending += Application_Suspending; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 시작시 처리하기 - OnLaunched(e) /// <summary> /// 시작시 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnLaunched(LaunchActivatedEventArgs e) { SystemNavigationManager.GetForCurrentView().BackRequested += SystemNavigationManager_BackRequested; Frame rootFrame = Window.Current.Content as Frame; if(rootFrame == null) { rootFrame = new Frame(); rootFrame.NavigationFailed += rootFrame_NavigationFailed; if(e.PreviousExecutionState == ApplicationExecutionState.Terminated) { } Window.Current.Content = rootFrame; } if(e.PrelaunchActivated == false) { if(rootFrame.Content == null) { rootFrame.Navigate(typeof(MainPage), e.Arguments); } Window.Current.Activate(); } #region 윈도우 크기를 설정한다. double width = 800d; double height = 600d; double dpi = (double)DisplayInformation.GetForCurrentView().LogicalDpi; ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize; Size windowSize = new Size(width * 96d / dpi, height * 96d / dpi); ApplicationView.PreferredLaunchViewSize = windowSize; Window.Current.Activate(); ApplicationView.GetForCurrentView().TryResizeView(windowSize); #endregion } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 애플리케이션 정지시 처리하기 - Application_Suspending(sender, e) /// <summary> /// 애플리케이션 정지시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void Application_Suspending(object sender, SuspendingEventArgs e) { SuspendingDeferral deferral = e.SuspendingOperation.GetDeferral(); deferral.Complete(); } #endregion #region 시스템 탐색 관리자 뒤로 이동 요청시 처리하기 - SystemNavigationManager_BackRequested(sender, e) /// <summary> /// 시스템 탐색 관리자 뒤로 이동 요청시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void SystemNavigationManager_BackRequested(object sender, BackRequestedEventArgs e) { Frame rootFrame = Window.Current.Content as Frame; if(rootFrame == null) { return; } if(rootFrame.CanGoBack && e.Handled == false) { e.Handled = true; rootFrame.GoBack(); } } #endregion #region 루트 프레임 네비게이션 실패시 처리하기 - rootFrame_NavigationFailed(sender, e) /// <summary> /// 루트 프레임 네비게이션 실패시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void rootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e) { throw new Exception($"페이지 로드를 실패했습니다 : {e.SourcePageType.FullName}"); } #endregion } } |
▶ MainPage.xaml
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
<Page x:Class="TestProject.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:TestProject" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" NavigationCacheMode="Enabled" FontFamily="나눔고딕코딩" FontSize="16"> <Page.Resources> <ItemsPanelTemplate x:Key="GridViewItemsPanelTemplateKey"> <ItemsWrapGrid HorizontalAlignment="Center" Orientation="Horizontal" /> </ItemsPanelTemplate> <DataTemplate x:Key="GridViewDataTemplateKey" x:DataType="local:Person"> <Grid Name="personGrid" Margin="10" Height="100" Width="100" Background="{x:Bind Brush}"> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock HorizontalAlignment="Center" Text="{x:Bind ID}" /> <TextBlock HorizontalAlignment="Center" Text="{x:Bind Name}" /> <TextBlock HorizontalAlignment="Center" Text="{x:Bind Age}" /> </StackPanel> </Grid> </DataTemplate> <Style x:Key="GridViewDefaultItemContainerStyleKey" TargetType="GridViewItem"> <Setter Property="Margin" Value="10" /> <Setter Property="Background" Value="LightGray" /> </Style> </Page.Resources> <Grid> <GridView Name="gridView" ItemsPanel="{StaticResource GridViewItemsPanelTemplateKey}" ItemTemplate="{StaticResource GridViewDataTemplateKey}" ItemContainerStyle="{StaticResource GridViewDefaultItemContainerStyleKey}" IsItemClickEnabled="True" ItemsSource="{x:Bind PersonCollection}" Loaded="{x:Bind gridView_Loaded}" ItemClick="gridView_ItemClick" /> </Grid> </Page> |
▶ MainPage.xaml.cs
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
using Microsoft.Toolkit.Uwp.UI.Animations; using System; using System.Collections.ObjectModel; using Windows.UI; using Windows.UI.Core; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Animation; using Windows.UI.Xaml.Navigation; namespace TestProject { /// <summary> /// 메인 페이지 /// </summary> public sealed partial class MainPage : Page { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 현재 사람 /// </summary> private Person currentPerson; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 사람 컬렉션 - PersonCollection /// <summary> /// 사람 컬렉션 /// </summary> public ObservableCollection<Person> PersonCollection { get; } = new ObservableCollection<Person>(); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainPage() /// <summary> /// 생성자 /// </summary> public MainPage() { InitializeComponent(); ItemsReorderAnimation.SetDuration(this.gridView, TimeSpan.FromMilliseconds(400)); } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 탐색되는 경우 처리하기 - OnNavigatedTo(e) /// <summary> /// 탐색되는 경우 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnNavigatedTo(NavigationEventArgs e) { SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Collapsed; if(PersonCollection.Count == 0) { AddPersion(100); } base.OnNavigatedTo(e); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 그리드 뷰 로드시 처리하기 - gridView_Loaded() /// <summary> /// 그리드 뷰 로드시 처리하기 /// </summary> private async void gridView_Loaded() { if(this.currentPerson != null) { this.gridView.ScrollIntoView(this.currentPerson); ConnectedAnimation animation = ConnectedAnimationService.GetForCurrentView().GetAnimation("backAnimation"); if(animation != null) { await this.gridView.TryStartConnectedAnimationAsync(animation, this.currentPerson, "personGrid"); } } } #endregion #region 그리드 뷰 항목 클릭시 처리하기 - gridView_ItemClick(sender, e) /// <summary> /// 그리드 뷰 항목 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void gridView_ItemClick(object sender, ItemClickEventArgs e) { this.currentPerson = e.ClickedItem as Person; this.gridView.PrepareConnectedAnimation("itemAnimation", e.ClickedItem, "personGrid"); Frame.Navigate(typeof(DetailPage), e.ClickedItem); } #endregion //////////////////////////////////////////////////////////////////////////////// Function #region 사람 추가하기 - AddPersion(count) /// <summary> /// 사람 추가하기 /// </summary> /// <param name="count">카운트</param> private void AddPersion(int count) { Random random = new Random(); for(int i = 0; i < count; i++) { Color color = Color.FromArgb ( 128, (byte)random.Next(0, 255), (byte)random.Next(0, 255), (byte)random.Next(0, 255) ); Person person = new Person ( i + 1, $"사람 {i + 1}", random.Next(0, 100), new SolidColorBrush(color) ); PersonCollection.Add(person); } } #endregion } } |
▶ DetailPage.xaml
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 |
<Page x:Class="TestProject.DetailPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" RequestedTheme="Dark"> <Grid> <RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid Name="personGrid" RelativePanel.AlignHorizontalCenterWithPanel="True" RelativePanel.AlignVerticalCenterWithPanel="True" Height="300" Width="300" Background="{x:Bind person.Brush}"> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock HorizontalAlignment="Center" Text="{x:Bind person.ID}" /> <TextBlock HorizontalAlignment="Center" Text="{x:Bind person.Name}" /> <TextBlock HorizontalAlignment="Center" Text="{x:Bind person.Age}" /> </StackPanel> </Grid> </RelativePanel> </Grid> </Page> |
▶ DetailPage.xaml.cs
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
using Windows.UI.Core; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media.Animation; using Windows.UI.Xaml.Navigation; namespace TestProject { /// <summary> /// 상세 페이지 /// </summary> public sealed partial class DetailPage : Page { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 사람 /// </summary> private Person person; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - DetailPage() /// <summary> /// 생성자 /// </summary> public DetailPage() { InitializeComponent(); } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 탐색되는 경우 처리하기 - OnNavigatedTo(e) /// <summary> /// 탐색되는 경우 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnNavigatedTo(NavigationEventArgs e) { this.person = e.Parameter as Person; if(this.person != null) { ConnectedAnimation animation = ConnectedAnimationService.GetForCurrentView().GetAnimation("itemAnimation"); if(animation != null) { animation.TryStart(this.personGrid); } } if(Frame.CanGoBack) { SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible; } else { SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Collapsed; } base.OnNavigatedTo(e); } #endregion #region 탐색하는 경우 처리하기 - OnNavigatingFrom(e) /// <summary> /// 탐색하는 경우 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) { if(e.NavigationMode == NavigationMode.Back) { ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("backAnimation", this.personGrid); } base.OnNavigatingFrom(e); } #endregion } } |