C#/C# 프로그래밍
[C#프로그래밍] [WPF] PC 카카오톡 만들기 #13 - ControlSlider(UserControl) 만들기
냠냠쿠
2023. 8. 30. 16:01
728x90
https://www.youtube.com/watch?v=iLDo5dc1hA4&list=PLlrfTSXS0LLKHfOfwM31jJw3SHuDnkF49&index=14
📌 Slider 애니메이션 적용하기
- Controls 폴더에 사용자정의 컨트롤 ControlSlider 파일 생성
-ControlSlider.xaml
<UserControl x:Class="wpfLib.Controls.ControlSlider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:wpfLib.Controls"
xmlns:converters="clr-namespace:wpfLib.Converters"
mc:Ignorable="d"
x:Name="root"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<!--애니메이션추가-->
<Storyboard
x:Key="SlideLeftToRight"
FillBehavior="Stop"
Completed="Slide_Complete">
<!--x좌표를 좌측 -> 우측 움직이는 애니메이션-->
<!--Duration : 움직이는시간-->
<DoubleAnimation
Duration="{Binding Duration, ElementName=root}"
Storyboard.TargetProperty="(RenderTransform).(TranslateTransform.X)"
From="{Binding ActualWidth, ElementName=root,
Converter={StaticResource InvertConverter}}"
To="0"
/>
</Storyboard>
</UserControl.Resources>
<Grid>
<ContentControl x:Name="content1">
<ContentControl.RenderTransform>
<TranslateTransform X="0" Y="0"/>
</ContentControl.RenderTransform>
</ContentControl>
<!--처음 기본으로 보일 화면-->
<ContentControl x:Name="content2">
<ContentControl.RenderTransform>
<TranslateTransform X="0" Y="0"/>
</ContentControl.RenderTransform>
</ContentControl>
</Grid>
</UserControl>
- Converters 폴더에 클래스파일 InvertConverter 추가
-InvertConverter.cs
namespace wpfLib.Converters
{
public class InvertConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return -(double)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
- 컨버터 추가 및 우측 애니메이션 추가
-ControlSlider.xaml
<UserControl.Resources>
<converters:InvertConverter x:Key="InvertConverter"/>
...
<!--우측-->
<DoubleAnimation
Duration="{Binding Duration, ElementName=root}"
Storyboard.TargetProperty="(RenderTransform).(TranslateTransform.X)"
From="0"
To="{Binding ActualWidth, ElementName=root}"
/>
-ControlSlider.xaml.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace wpfLib.Controls
{
/// <summary>
/// ControlSlider.xaml에 대한 상호 작용 논리
/// </summary>
public partial class ControlSlider : UserControl, INotifyPropertyChanged
{
private ContentControl _backContent;
private ContentControl _frontContent;
private Storyboard _slideLeftToRight;
//private Storyboard _slideRightToLeft;
//private Storyboard _slideTopToBottom;
//private Storyboard _slideBottomToTop;
private Duration? _duration;
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ControlSlider()
{
InitializeComponent();
_slideLeftToRight = (Storyboard)Resources["SlideLeftToRight"];
//_slideRightToLeft = (Storyboard)Resources["SlideRightToLeft"];
//_slideTopToBottom = (Storyboard)Resources["SlideTopToBottom"];
//_slideBottomToTop = (Storyboard)Resources["SlideBottomToTop"];
//_backContent : 처음 보여질 Content
_backContent = content2;
_frontContent = content1;
}
private void Slide_Complate(Object sender, EventArgs e)
{
}
//최초 Content 추가하는 함수 생성
public void InitContent(object newContent)
{
//만약 Content가 null이면 초기화
_frontContent.Content = null;
_backContent.Content = newContent;
}
//슬라이드 호출 함수
public void Slide(object newContent, SlideType slideType)
{
if (_backContent.Content == null)
{
InitContent(newContent);
return;
}
}
//애니메이션 속도를 조정 할 수 있도록 함수 생성
public void SetAnimationSpeed(int milliseconds)
{
Duration = new Duration(new TimeSpan(0, 0, 0, 0, milliseconds));
}
public Duration? Duration
{
get
{
if (_duration == null)
{
// Duration 기본 1초로 설정
_duration = new Duration(new TimeSpan(0, 0, 1));
}
return _duration;
}
set
{
if (_duration != value)
{
//// Duration 이 value와 다르다면 OnPropertyChanged 실행
_duration = value;
OnPropertyChanged();
}
}
}
}
}
-SlideType.cs
namespace wpfLib.Controls
{
public enum SlideType
{
LeftToRight, RightToLeft, TopToBottom, BottomToTop
}
}
-ControlSlider.xaml.cs
//슬라이드 호출 함수
public void Slide(object newContent, SlideType slideType)
{
if (_backContent.Content == null)
{
//만약 Content가 null이면 초기화
InitContent(newContent);
return;
}
_frontContent = _backContent == content2 ? content1 : content2;
_frontContent.Visibility = Visibility.Visible;
_frontContent.Content = newContent;
switch (slideType)
{
case SlideType.LeftToRight:
break;
case SlideType.RightToLeft:
break;
case SlideType.TopToBottom:
break;
case SlideType.BottomToTop:
break;
}
}
-ControlSlider.xaml.cs
//슬라이드 호출 함수
public void Slide(object newContent, SlideType slideType)
{
if (_backContent.Content == null)
{
//만약 Content가 null이면 초기화
InitContent(newContent);
return;
}
_frontContent = _backContent == content2 ? content1 : content2;
_frontContent.Visibility = Visibility.Visible;
_frontContent.Content = newContent;
switch (slideType)
{
case SlideType.LeftToRight:
BeginSlideStoryboard(_slideLeftToRight);
break;
case SlideType.RightToLeft:
//BeginSlideStoryboard(_slideRightToLeft);
break;
case SlideType.TopToBottom:
//BeginSlideStoryboard(_slideTopToBottom);
break;
case SlideType.BottomToTop:
//BeginSlideStoryboard(_slideBottomToTop);
break;
}
}
private void BeginSlideStoryboard(Storyboard storyboard)
{
// front는 항상 좌 -> 우
// back은 최초 한번 이후 뒤에 숨겨짐
Storyboard.SetTarget(storyboard.Children[0], _frontContent);
Storyboard.SetTarget(storyboard.Children[1], _backContent);
storyboard.Begin();
}
-ControlSlider.xaml.cs
private void Slide_Complete(object sender, EventArgs e)
{
//back은 숨김
_backContent.Visibility = Visibility.Collapsed;
//back에 front Content할당
_backContent = _frontContent;
}
Back에 frontContent 할당하는 이유
: Back은 보이지 않는 화면인데 다음에 frontContent 할당을 해 두면 다음에 들어오게 될 때 비교 대상이 frontContent가 된다.
그래서 frontContent가 다시 backContent가 되는 것이고 frontContent는 새로운 content가 들어오게 되는 것이다.
- 주석 처리 했던 것들 모두 주석 풀어주기
📌 작동 Test 하기
- 솔루션에 프로젝트 WpfControlSlider 추가 및 참조추가로 WpfLib 등록한 뒤 ViewModel 생성
- firstView.xaml
<Grid Background="Green">
<TextBlock Text="firstView" FontSize="50"/>
</Grid>
- SecondView.xaml
<Grid Background="Yellow">
<TextBlock Text="secondView" FontSize="50"/>
</Grid>
- MainWindow.xaml
<Window x:Class="WpfControlSlider.MainWindow"
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:local="clr-namespace:WpfControlSlider" xmlns:controls="clr-namespace:wpfLib.Controls;assembly=wpfLib"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<controls:ControlSlider Grid.Row="0" x:Name="slider"/>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="LeftToRight" Click="LeftToRight_Clicked"/>
<Button Grid.Column="1" Content="RightToLeft" Click="RightToLeft_Clicked"/>
<Button Grid.Column="2" Content="TopToBottom" Click="TopToBottom_Clicked"/>
<Button Grid.Column="3" Content="BottomToTop" Click="BottomToTop_Clicked"/>
</Grid>
</Grid>
</Window>
- MainWindow.xaml
<Window.Resources>
<DataTemplate DataType="{x:Type viewmodels:FirstViewModel}">
<views:FirstView/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:SecondViewModel}">
<views:SecondView/>
</DataTemplate>
</Window.Resources>
- MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WpfControlSlider.ViewModels;
using wpfLib.ViewModels;
namespace WpfControlSlider
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ViewModelBase _currentViewModel = default;
public ViewModelBase CurrentViewModel
{
get
{
if (_currentViewModel is FirstViewModel)
{
_currentViewModel = new SecondViewModel();
}
else
{
_currentViewModel = new FirstViewModel();
}
return _currentViewModel;
}
}
public MainWindow()
{
InitializeComponent();
}
private void LeftToRight_Clicked(object sender, RoutedEventArgs e)
{
slider.SetAnimationSpeed(100);
slider.Slide(CurrentViewModel, wpfLib.Controls.SlideType.LeftToRight);
}
private void RightToLeft_Clicked(object sender, RoutedEventArgs e)
{
slider.SetAnimationSpeed(300);
slider.Slide(CurrentViewModel, wpfLib.Controls.SlideType.RightToLeft);
}
private void TopToBottom_Clicked(object sender, RoutedEventArgs e)
{
slider.SetAnimationSpeed(700);
slider.Slide(CurrentViewModel, wpfLib.Controls.SlideType.TopToBottom);
}
private void BottomToTop_Clicked(object sender, RoutedEventArgs e)
{
slider.SetAnimationSpeed(1000);
slider.Slide(CurrentViewModel, wpfLib.Controls.SlideType.BottomToTop);
}
}
}
이 상태에서 실행을 해 보면 애니메이션이 적용 된 모습을 확인 할 수 있다.
728x90