첨부 소스 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

TestProject.zip
다운로드

▶ MainWindow.xaml

<Window x:Class="TestProject.MainWindow" Name="window"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="800"
    Height="700"
    Title="스플라인 키 프레임 애니메이션 사용하기"
    FontFamily="나눔고딕코딩"
    FontSize="16">
    <Canvas>
        <Canvas Name="mainCanvas" Canvas.Left="25" Canvas.Top="25">
            <Line
                X1="50"
                Y1="00"
                X2="275"
                Y2="00" 
                Stroke="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
            <TextBlock Canvas.Left="275" Canvas.Top="-10"
                Text=" 시간 " />
            <Line
                X1="325"
                Y1="0"
                X2="550"
                Y2="0"
                Stroke="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
            <Canvas Canvas.Left="50" Canvas.Top="50"
                Width="500"
                Height="500"
                Background="LightGray"
                MouseDown="gridCanvas_MouseDown"
                MouseMove="gridCanvas_MouseDown">
                <Path
                    Stroke="Black"
                    StrokeThickness="0.005">
                    <Path.Data>
                        <PathGeometry>
                            <PathFigure StartPoint="0 0">
                                <BezierSegment 
                                    Point1="{Binding ElementName=window, Path=ControlPoint1}"
                                    Point2="{Binding ElementName=window, Path=ControlPoint2}"
                                    Point3="1 1" />
                            </PathFigure>
                        </PathGeometry>
                    </Path.Data>
                    <Path.RenderTransform>
                        <ScaleTransform ScaleX="500" ScaleY="500" />
                    </Path.RenderTransform>
                </Path>
                <Line
                    Stroke="DarkGray"
                    StrokeThickness="0.005"
                    X1="0"
                    Y1="0"
                    X2="{Binding ElementName=window, Path=ControlPoint1.X}"
                    Y2="{Binding ElementName=window, Path=ControlPoint1.Y}">
                    <Line.RenderTransform>
                        <ScaleTransform ScaleX="500" ScaleY="500" />
                    </Line.RenderTransform>
                </Line>
                <Line
                    Stroke="DarkGray"
                    StrokeThickness="0.005"
                    X1="1"
                    Y1="1"
                    X2="{Binding ElementName=window, Path=ControlPoint2.X}"
                    Y2="{Binding ElementName=window, Path=ControlPoint2.Y}">
                    <Line.RenderTransform>
                        <ScaleTransform ScaleX="500" ScaleY="500" />
                    </Line.RenderTransform>
                </Line>
            </Canvas>
        </Canvas>
        <Path Name="timePath" Fill="Blue">
            <Path.Data>
                <EllipseGeometry
                    Center="75 575"
                    RadiusX="6"
                    RadiusY="6" />
            </Path.Data>
        </Path>
        <Path Name="valuePath" Fill="Blue">
            <Path.Data>
                <EllipseGeometry
                    Center="575 75"
                    RadiusX="6"
                    RadiusY="6" />
            </Path.Data>
        </Path>
        <Line
            Stroke="Blue"
            X1="{Binding ElementName=timePath, Path=Data.Center.X}"
            Y1="{Binding ElementName=valuePath, Path=Data.Center.Y}"
            X2="{Binding ElementName=timePath, Path=Data.Center.X}"
            Y2="575" />
        <Line Stroke="Blue"
              X1="{Binding ElementName=timePath, Path=Data.Center.X}"
              Y1="{Binding ElementName=valuePath, Path=Data.Center.Y}"
              X2="575" 
              Y2="{Binding ElementName=valuePath, Path=Data.Center.Y}" />
        <Label Name="informationLabel"
            Canvas.Left="75"
            Canvas.Top="600" />
        <Button
            Canvas.Left="625"
            Canvas.Top="575"
            Width="100"
            Height="30"
            Content="실행">
            <Button.Triggers>
                <EventTrigger RoutedEvent="Button.Click">
                    <BeginStoryboard>
                        <Storyboard>
                            <PointAnimation 
                                Storyboard.TargetName="timePath"
                                Storyboard.TargetProperty="Data.Center"
                                Duration="0:0:5"
                                From="75 575"
                                To="575 575"/>
                            <PointAnimationUsingKeyFrames 
                                Storyboard.TargetName="valuePath"
                                Storyboard.TargetProperty="Data.Center">
                                <DiscretePointKeyFrame KeyTime="0:0:0" Value="575 75" />
                                <SplinePointKeyFrame   KeyTime="0:0:5" Value="575 575">
                                    <SplinePointKeyFrame.KeySpline>
                                        <KeySpline x:Name="keySpline" />
                                    </SplinePointKeyFrame.KeySpline>
                                </SplinePointKeyFrame>
                            </PointAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Button.Triggers>
        </Button>
    </Canvas>
</Window>

 

728x90

 

▶ MainWindow.xaml.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace TestProject
{
    /// <summary>
    /// 메인 윈도우
    /// </summary>
    public partial class MainWindow : Window
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 제어점 1 속성
        /// </summary>
        public static DependencyProperty ControlPoint1Property = DependencyProperty.Register
        (
            "ControlPoint1",
            typeof(Point),
            typeof(MainWindow),
            new PropertyMetadata
            (
                new Point(0, 0),
                ControlPointProperty_PropertyChangedCallback
            )
        );

        /// <summary>
        /// 제어점 2 속성
        /// </summary>
        public static DependencyProperty ControlPoint2Property = DependencyProperty.Register
        (
            "ControlPoint2",
            typeof(Point),
            typeof(MainWindow),
            new PropertyMetadata
            (
                new Point(1, 1),
                ControlPointProperty_PropertyChangedCallback
            )
        );

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 제어점 1 - ControlPoint1

        /// <summary>
        /// 제어점 1
        /// </summary>
        public Point ControlPoint1
        {
            set
            {
                SetValue(ControlPoint1Property, value);
            }
            get
            {
                return (Point)GetValue(ControlPoint1Property);
            }
        }

        #endregion
        #region 제어점 2 - ControlPoint2

        /// <summary>
        /// 제어점 2
        /// </summary>
        public Point ControlPoint2
        {
            set
            {
                SetValue(ControlPoint2Property, value);
            }
            get
            {
                return (Point)GetValue(ControlPoint2Property);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainWindow()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            for(int i = 0; i <= 10; i++)
            {
                TextBlock horizontalTextBlock = new TextBlock();

                horizontalTextBlock.Text = (i / 10m).ToString("N1");

                this.mainCanvas.Children.Add(horizontalTextBlock);

                Canvas.SetLeft(horizontalTextBlock, 40 + 50 * i);
                Canvas.SetTop (horizontalTextBlock, 14         );

                Line horizontalLine = new Line();

                horizontalLine.Stroke = Brushes.Black;
                horizontalLine.X1     = 50 * (i + 1);
                horizontalLine.Y1     = 35;
                horizontalLine.X2     = horizontalLine.X1;
                horizontalLine.Y2     = 550;

                mainCanvas.Children.Add(horizontalLine);

                TextBlock verticalTextBlock = new TextBlock();

                verticalTextBlock.Text = (i / 10m).ToString("N1");

                this.mainCanvas.Children.Add(verticalTextBlock);

                Canvas.SetLeft(verticalTextBlock, 5          );
                Canvas.SetTop (verticalTextBlock, 40 + 50 * i);

                Line verticalLine = new Line();

                verticalLine.Stroke = Brushes.Black;

                verticalLine.X1     = 35;
                verticalLine.Y1     = 50 * (i + 1);
                verticalLine.X2     = 550;
                verticalLine.Y2     = verticalLine.Y1;

                this.mainCanvas.Children.Add(verticalLine);
            }

            UpdateInformation();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private
        ////////////////////////////////////////////////////////////////////// Event

        #region 제어점 속성 속성 변경시 콜백 처리하기 - ControlPointProperty_PropertyChangedCallback(d, e)

        /// <summary>
        /// 제어점 속성 속성 변경시 콜백 처리하기
        /// </summary>
        /// <param name="d">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private static void ControlPointProperty_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MainWindow mainWindow = d as MainWindow;

            if(e.Property == ControlPoint1Property)
            {
                mainWindow.keySpline.ControlPoint1 = (Point)e.NewValue;
            }
            else if(e.Property == ControlPoint2Property)
            {
                mainWindow.keySpline.ControlPoint2 = (Point)e.NewValue;
            }
        }

        #endregion

        ////////////////////////////////////////////////////////////////////// Function

        #region 프로그램 시작하기 - Main()

        /// <summary>
        /// 프로그램 시작하기
        /// </summary>
        [STAThread]
        private static void Main()
        {
            Application application = new Application();

            application.Run(new MainWindow());
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Private
        ////////////////////////////////////////////////////////////////////// Event

        #region 그리드 캔버스 마우스 하강시 처리하기 - gridCanvas_MouseDown(sender, e)

        /// <summary>
        /// 그리드 캔버스 마우스 하강시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void gridCanvas_MouseDown(object sender, MouseEventArgs e)
        {
            Canvas gridCanvas = sender as Canvas;
            Point  mousePoint = e.GetPosition(gridCanvas);

            mousePoint.X = Math.Min(1, Math.Max(0, mousePoint.X / gridCanvas.ActualWidth ));
            mousePoint.Y = Math.Min(1, Math.Max(0, mousePoint.Y / gridCanvas.ActualHeight));

            if(e.LeftButton == MouseButtonState.Pressed)
            {
                ControlPoint1 = mousePoint;
            }

            if(e.RightButton == MouseButtonState.Pressed)
            {
                ControlPoint2 = mousePoint;
            }

            if(e.LeftButton == MouseButtonState.Pressed ||  e.RightButton == MouseButtonState.Pressed)
            {
                UpdateInformation();
            }
        }

        #endregion
        #region 정보 갱신하기 - UpdateInformation()

        /// <summary>
        /// 정보 갱신하기
        /// </summary>
        private void UpdateInformation()
        {
            informationLabel.Content = string.Format
            (
                "왼쪽 마우스 버튼이 제어점 1을 변경하였습니다 : ({0:F2})\n" +
                "오른쪽 마우스 버튼이 제어점 2를 변경하였습니다 : ({1:F2})",
                ControlPoint1,
                ControlPoint2
            );
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요