■ Connected 엘리먼트의 Key/AnchorElement/ListItemKey/ListItemElementName 첨부 속성을 사용해 연결 애니메이션을 만드는 과정을 보여준다.
※ 이 예제 코드에서 사용된 Connected 엘리먼트는 CommunityToolkit.WinUI.Animations 누겟(버전 : 8.0.240109)을 참조한다.
※ 비주얼 스튜디오에서 TestProject(Unpackaged) 모드로 빌드한다.
※ TestProject.csproj 프로젝트 파일에서 WindowsPackageType 태그를 None으로 추가했다.
▶ FirstPage.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 |
<?xml version="1.0" encoding="utf-8"?> <Page x:Class="TestProject.FirstPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ctwa="using:CommunityToolkit.WinUI.Animations" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" FontFamily="나눔고딕코딩" FontSize="16"> <StackPanel Margin="30" Orientation="Vertical" Spacing="30"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Top" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="This is the first page, Click or Tap the box to navigate to the next page" /> <Border Name="border" HorizontalAlignment="Center" VerticalAlignment="Center" Width="120" Height="120" CornerRadius="{StaticResource ControlCornerRadius}" Background="{ThemeResource AccentFillColorDefaultBrush}" ctwa:Connected.Key="item" /> </StackPanel> </Page> |
▶ FirstPage.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 |
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Media.Animation; namespace TestProject; /// <summary> /// 첫번째 페이지 /// </summary> public sealed partial class FirstPage : Page { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - FirstPage() /// <summary> /// 생성자 /// </summary> public FirstPage() { InitializeComponent(); this.border.Tapped += border_Tapped; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 테두리 탭 처리하기 - border_Tapped(sender, e) /// <summary> /// 테두리 탭 처리하기 /// </summary> /// <param name="sender">이벤트 인자</param> /// <param name="e">이벤트 발생자</param> private void border_Tapped(object sender, TappedRoutedEventArgs e) { Frame.Navigate(typeof(SecondPage), null, new SuppressNavigationTransitionInfo()); } #endregion } |
▶ SecondPage.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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
<?xml version="1.0" encoding="utf-8"?> <Page x:Class="TestProject.SecondPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ctwa="using:CommunityToolkit.WinUI.Animations" xmlns:local="using:TestProject" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" FontFamily="나눔고딕코딩" FontSize="16"> <Grid Padding="30" RowSpacing="30"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <StackPanel Grid.Row="0" Orientation="Horizontal"> <Border Name="border" Width="120" Height="120" CornerRadius="{StaticResource ControlCornerRadius}" Background="{ThemeResource AccentFillColorDefaultBrush}" ctwa:Connected.Key="item" /> <StackPanel VerticalAlignment="Bottom" Margin="25 0" MaxWidth="500" ctwa:Connected.AnchorElement="{x:Bind border}"> <TextBlock Style="{StaticResource TitleTextBlockStyle}" Text="Header" /> <TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" TextWrapping="WrapWholeWords" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce eleifend ex sit amet blandit lobortis. Curabitur ut diam fringilla, interdum massa sit amet, facilisis erat. Donec vulputate sed ex vel pellentesque. In sodales odio non felis interdum viverra. Morbi in mi mollis, ullamcorper nibh sit amet, sagittis ex. Maecenas dapibus commodo venenatis. Donec at egestas est." /> </StackPanel> </StackPanel> <GridView Name="gridView" Grid.Row="1" SelectionMode="None" IsItemClickEnabled="True" ctwa:Connected.ListItemElementName="image" ctwa:Connected.ListItemKey="details"> <GridView.ItemTemplate> <DataTemplate x:DataType="local:Photo"> <Grid Width="120" Height="120"> <Image Name="image" Stretch="UniformToFill" Source="{x:Bind Thumbnail}" /> <Border VerticalAlignment="Bottom" Background="{ThemeResource ControlOnImageFillColorDefaultBrush}" Padding="10"> <TextBlock FontSize="14" Text="{x:Bind Title}" /> </Border> </Grid> </DataTemplate> </GridView.ItemTemplate> </GridView> </Grid> </Page> |
▶ SecondPage.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 |
using System.Collections.ObjectModel; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media.Animation; using Microsoft.UI.Xaml.Navigation; namespace TestProject; /// <summary> /// 두번째 페이지 /// </summary> public sealed partial class SecondPage : Page { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 포토 컬렉션 /// </summary> private static ObservableCollection<Photo> _photoCollection; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - SecondPage() /// <summary> /// 생성자 /// </summary> public SecondPage() { InitializeComponent(); this.gridView.ItemClick += gridView_ItemClick; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected //////////////////////////////////////////////////////////////////////////////// Function #region 탐색 진입시 처리하기 - OnNavigatedTo(e) /// <summary> /// 탐색 진입시 처리하기 /// </summary> /// <param name="e">이벤트 발생자</param> protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); if(_photoCollection == null) { _photoCollection = new ObservableCollection<Photo> { new Photo { Title = "Big Four Summer Heat", Thumbnail = "ms-appx:///IMAGE/BigFourSummerHeat2.jpg", }, new Photo { Title = "Bison Badlands Chillin", Thumbnail = "ms-appx:///IMAGE/BisonBadlandsChillin2.jpg", }, new Photo { Title = "Columbia River Gorge", Thumbnail = "ms-appx:///IMAGE/ColumbiaRiverGorge.jpg", }, new Photo { Title = "Grand Tetons", Thumbnail = "ms-appx:///IMAGE/GrandTetons.jpg", }, new Photo { Title = "Oregon Winery Namaste", Thumbnail = "ms-appx:///IMAGE/OregonWineryNamaste.jpg", }, new Photo { Title = "Running Dog Pacific City", Thumbnail = "ms-appx:///IMAGE/RunningDogPacificCity.jpg", } }; } this.gridView.ItemsSource = _photoCollection; } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private //////////////////////////////////////////////////////////////////////////////// Event #region 그리드 뷰 항목 클릭시 처리하기 - gridView_ItemClick(sender, e) /// <summary> /// 그리드 뷰 항목 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void gridView_ItemClick(object sender, ItemClickEventArgs e) { Frame.Navigate(typeof(ThirdPage), e.ClickedItem, new SuppressNavigationTransitionInfo()); } #endregion } |
▶ ThirdPage.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 |
<?xml version="1.0" encoding="utf-8"?> <Page x:Class="TestProject.ThirdPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ctwa="using:CommunityToolkit.WinUI.Animations" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" FontFamily="나눔고딕코딩" FontSize="16"> <Grid Padding="32"> <StackPanel> <StackPanel HorizontalAlignment="Right" Orientation="Horizontal"> <StackPanel VerticalAlignment="Bottom" Margin="25 0" MaxWidth="500" ctwa:Connected.AnchorElement="{x:Bind image}"> <TextBlock Style="{StaticResource TitleTextBlockStyle}" Text="{x:Bind Photo.Title}" /> <TextBlock Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce eleifend ex sit amet blandit lobortis. Curabitur ut diam fringilla, interdum massa sit amet, facilisis erat. Donec vulputate sed ex vel pellentesque. In sodales odio non felis interdum viverra. Morbi in mi mollis, ullamcorper nibh sit amet, sagittis ex. Maecenas dapibus commodo venenatis. Donec at egestas est." TextWrapping="WrapWholeWords" /> </StackPanel> <Border CornerRadius="{StaticResource ControlCornerRadius}"> <Image Name="image" Width="120" Height="120" ctwa:Connected.Key="details" Source="{x:Bind Photo.Thumbnail}" /> </Border> </StackPanel> <TextBlock Margin="0 30" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce eleifend ex sit amet blandit lobortis. Curabitur ut diam fringilla, interdum massa sit amet, facilisis erat. Donec vulputate sed ex vel pellentesque. In sodales odio non felis interdum viverra. Morbi in mi mollis, ullamcorper nibh sit amet, sagittis ex. Maecenas dapibus commodo venenatis. Donec at egestas est. Donec sit amet ante gravida, feugiat arcu quis, ullamcorper justo. Donec finibus erat lectus, pretium ultrices erat lobortis eu. Nulla sodales libero nisi, a varius urna vehicula et. In rhoncus magna sed felis ultricies aliquet. Sed rhoncus mi id elementum faucibus. Fusce blandit, urna sit amet maximus ultrices, lorem neque fermentum felis, id elementum tellus erat eu eros. Vivamus egestas, est eu sagittis vehicula, lorem nulla hendrerit elit, eu consectetur leo magna eu lorem. Nulla pulvinar augue vitae libero pretium molestie. Nam eget dui velit. Curabitur eu vehicula velit, eu convallis orci. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vestibulum et ipsum turpis. Ut volutpat condimentum elit, sit amet faucibus libero dignissim ac. Aenean vitae euismod lorem. Cras enim neque, hendrerit et dui vitae, viverra porttitor nisi. Aliquam suscipit dictum leo id consequat. Pellentesque condimentum elementum neque. Donec hendrerit nisi quis lorem sagittis, et aliquam dui suscipit. Cras at ligula vitae magna dignissim condimentum nec sagittis mauris. In hac habitasse platea dictumst. Donec tempor, dui et pretium pretium, libero magna iaculis eros, sed consequat nisi orci tempus est. Fusce in rutrum odio. Donec vitae porta metus, et pellentesque turpis. Nullam vestibulum lacus a metus sollicitudin vestibulum. Quisque lacinia quam et urna iaculis mattis. Vestibulum in justo ligula. Donec in dolor lacinia, semper risus eget, bibendum libero. Phasellus elementum odio vel facilisis gravida. Aliquam ac rutrum lacus, et aliquam arcu. Sed tempor rhoncus ipsum, nec viverra diam suscipit non. Nam fermentum commodo auctor. Praesent et nunc id nibh dignissim interdum. Phasellus fermentum mauris tortor, vel laoreet leo maximus sed. Nam sagittis risus lacinia quam dictum rutrum. Pellentesque mollis elit vel mauris eleifend auctor. Donec nec tincidunt odio. Morbi eleifend, turpis ullamcorper convallis vehicula, eros enim lobortis sapien, sit amet consequat risus lorem eu ligula. Quisque hendrerit scelerisque justo vel ultricies. Duis nec erat vulputate, sagittis nisi ut, congue tellus. Integer eget risus nec justo rutrum gravida. Sed eu aliquam nisl, consectetur euismod lacus. Etiam erat ligula, laoreet sed risus non, auctor sollicitudin lacus. Ut tincidunt lectus nec tempor interdum. Proin varius nisi enim, sed finibus urna tincidunt et. Suspendisse venenatis ex ut risus porttitor tempor. Vestibulum mauris ante, blandit in bibendum ac, aliquet quis leo. Aenean at facilisis nunc. Nullam blandit erat at orci tincidunt, in iaculis lorem viverra. Maecenas nec dui porta, tempus nulla nec, rhoncus felis. Ut vitae lectus a metus varius pretium at ut enim. Suspendisse potenti." TextWrapping="WrapWholeWords" /> </StackPanel> </Grid> </Page> |
▶ ThirdPage.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 |
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Navigation; namespace TestProject; /// <summary> /// 세번째 페이지 /// </summary> public sealed partial class ThirdPage : Page { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 포토 - Photo /// <summary> /// 포토 /// </summary> public Photo Photo { get; set; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - ThirdPage() /// <summary> /// 생성자 /// </summary> public ThirdPage() { InitializeComponent(); } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 탐색 진입시 처리하기 - OnNavigatedTo(e) /// <summary> /// 탐색 진입시 처리하기 /// </summary> /// <param name="e">이벤트 인자</param> protected override void OnNavigatedTo(NavigationEventArgs e) { if(e.Parameter is Photo photoItem) { Photo = photoItem; } base.OnNavigatedTo(e); } #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 |
<?xml version="1.0" encoding="utf-8"?> <Page x:Class="TestProject.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ctw="using:CommunityToolkit.WinUI" xmlns:ctwa="using:CommunityToolkit.WinUI.Animations" xmlns:local="using:TestProject" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" FontFamily="나눔고딕코딩" FontSize="16"> <Grid Margin="10"> <Border BorderThickness="1" BorderBrush="{ThemeResource SurfaceStrokeColorDefaultBrush}" CornerRadius="{StaticResource OverlayCornerRadius}" Background="{ThemeResource SolidBackgroundFillColorBaseBrush}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Border Grid.Row="0" Background="{StaticResource SolidBackgroundFillColorSecondaryBrush}"> <StackPanel VerticalAlignment="Top" Height="32" Orientation="Horizontal"> <Button Name="backButton" Margin="5 0 0 0" Content="{ctw:FontIcon Glyph=, FontSize=14}" Visibility="Collapsed" /> <TextBlock Style="{StaticResource CaptionTextBlockStyle}" VerticalAlignment="Center" Margin="10 0" Text="My Connected Animations App"> <ctwa:Implicit.Animations> <ctwa:OffsetAnimation Duration="00:00:00.3" /> </ctwa:Implicit.Animations> </TextBlock> </StackPanel> </Border> <Frame Name="rootFrame" Grid.Row="1" /> </Grid> </Border> </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 |
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media.Animation; using Microsoft.UI.Xaml.Navigation; namespace TestProject; /// <summary> /// 메인 페이지 /// </summary> public sealed partial class MainPage : Page { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainPage() /// <summary> /// 생성자 /// </summary> public MainPage() { InitializeComponent(); this.backButton.Click += backButton_Click; this.rootFrame.Navigating += rootFrame_Navigating; this.rootFrame.Navigated += rootFrame_Navigated; this.rootFrame.Navigate(typeof(FirstPage)); } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region Back 버튼 클릭시 처리하기 - backButton_Click(sender, e) /// <summary> /// Back 버튼 클릭시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void backButton_Click(object sender, RoutedEventArgs e) { this.rootFrame.GoBack(new SuppressNavigationTransitionInfo()); } #endregion #region 루트 프레임 네비게이션 완료시 처리하기 - rootFrame_Navigated(sender, e) /// <summary> /// 루트 프레임 네비게이션 완료시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void rootFrame_Navigated(object sender, NavigationEventArgs e) { this.backButton.Visibility = rootFrame.CanGoBack ? Visibility.Visible : Visibility.Collapsed; } #endregion #region 루트 프레임 네비게이션 진행시 처리하기 - rootFrame_Navigating(sender, e) /// <summary> /// 루트 프레임 네비게이션 진행시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void rootFrame_Navigating(object sender, NavigatingCancelEventArgs e) { if(e.SourcePageType == rootFrame.SourcePageType) { e.Cancel = true; } } #endregion } |