편집용 Canvas 만들기




목차


개발을 하다보면, 포토샵이나 PowerPoint 처럼 캔버스가 필요합니다. 그런데 이 캔버스는 무한히 확장되는 특성을 가지고 있지요. 이런 캔버스를 만들어 보도록 하겠습니다.




개요


이전 포스팅에서 사용했던 것들을 섞어서 만들었습니다. 단 스크롤바는 없앴는데, 이게 너무 문제가 많습니다. -_-; 기존 ScrollViewer 를 가지고 뭔가 하려고 하면, 수정의 수정이 필요하고, 꼬리를 무네요. 그래서 간단한 방식으로 바꾸어 보았습니다.


지원되는 내용은 다음과 같습니다.


1. 캔버스 위의 각 오브젝트들은 마우스 좌클릭을 통해서 이동시킬 수 있다.

2. 오브젝트들은 상호 트리개념이 있어서, parent 가 움직이면, 해당 child 도 같이 움직인다.

3. 캔버스의 이동은 마우스 가운데 버튼을 클릭한 상태로 움직이면 된다.



소스코드는 기존의 FlottingGrid 와 DragOnCanvasBehavior 를 사용하였고, 새로 MovingCanvas 라는 것을 만들었습니다.

이것은 마우스 가운데 버튼을 통해서 캔버스를 움직이는데 사용됩니다.

참, DraggableCanvas 도 수정되었습니다.


이 두 가지 소스코드만 올리도록 하겠습니다. 나머진 이전 포스팅을 참고하세요 :)








    [DraggableCanvas]



<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:SW.Common.Controls"
                    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
                    xmlns:sw="http://wpf.sungwook.kim/common">
    <Style TargetType="{x:Type local:DraggableCanvas}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TreeView}">
                    <ControlTemplate.Resources>
                        <Style TargetType="{x:Type TreeViewItem}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type TreeViewItem}">
                                        <Canvas x:Name="PART_Canvas">
                                            <ContentPresenter Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}"
                                                              Canvas.Left="{Binding (Canvas.Left)}"
                                                              Canvas.Right="{Binding (Canvas.Right)}"
                                                              Canvas.Top="{Binding (Canvas.Top)}"
                                                              Canvas.Bottom="{Binding (Canvas.Bottom)}">
                                                <i:Interaction.Behaviors>
                                                    <sw:DragOnCanvasBehavior BaseElement="{Binding RelativeSource={RelativeSource AncestorType=local:DraggableCanvas}}"
                                                                                    Target="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}}"/>
                                                </i:Interaction.Behaviors>
                                            </ContentPresenter>
                                            <ItemsPresenter/>
                                        </Canvas>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>

                            <Setter Property="ItemsPanel">
                                <Setter.Value>
                                    <ItemsPanelTemplate>
                                        <Canvas/>
                                    </ItemsPanelTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ControlTemplate.Resources>

                    <local:FlottingGrid GridOffsetX="{Binding ElementName=PART_RootCanvas, Path=OffsetX}"
                                        GridOffsetY="{Binding ElementName=PART_RootCanvas, Path=OffsetY}"
                                        Background="{TemplateBinding Background}">
                        <local:MovingCanvas Background="Transparent" x:Name="PART_RootCanvas" IsItemsHost="True"/>
                    </local:FlottingGrid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>




    [MovingCanvas]



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.Input;
using MS.Internal;

namespace SW.Common.Controls
{
    public class MovingCanvas : Canvas
    {
        public double OffsetX
        {
            get { return (double)GetValue(OffsetXProperty); }
            set { SetValue(OffsetXProperty, value); }
        }

        // Using a DependencyProperty as the backing store for OffsetX.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OffsetXProperty =
            DependencyProperty.Register("OffsetX", typeof(double), typeof(MovingCanvas), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure));




        public double OffsetY
        {
            get { return (double)GetValue(OffsetYProperty); }
            set { SetValue(OffsetYProperty, value); }
        }

        // Using a DependencyProperty as the backing store for OffsetY.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OffsetYProperty =
            DependencyProperty.Register("OffsetY", typeof(double), typeof(MovingCanvas), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure));




        private Point _initMousePosition;
        private Point _initItemPosition;
        private bool _onDrag = false;
        private Cursor _prevCursor;


        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            if (this._onDrag == false && e.MiddleButton == MouseButtonState.Pressed)
            {
                this._onDrag = true;
                this._prevCursor = this.Cursor;
                this.Cursor = Cursors.ScrollAll;
                this._initMousePosition = e.GetPosition(this);

                this._initItemPosition = new Point(this.OffsetX, this.OffsetY);
                this.CaptureMouse();
            }
            base.OnMouseDown(e);
        }


        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (e.MiddleButton == MouseButtonState.Pressed && this._onDrag == true)
            {
                Vector delta = e.GetPosition(this) - this._initMousePosition;
                this.OffsetX = this._initItemPosition.X + delta.X;
                this.OffsetY = this._initItemPosition.Y + delta.Y;
            }

            base.OnMouseMove(e);
        }


        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
            this._onDrag = false;
            this.Cursor = this._prevCursor;
            this.ReleaseMouseCapture();

            base.OnMouseUp(e);
        }




        protected override Size ArrangeOverride(Size arrangeSize)
        {
            foreach (UIElement element in this.InternalChildren)
            {
                if (element != null)
                {
                    double x = 0.0;
                    double y = 0.0;
                    double left = Canvas.GetLeft(element);
                    if (!double.IsNaN(left))
                    {
                        x = left;
                    }
                    else
                    {
                        double right = Canvas.GetRight(element);
                        if (!double.IsNaN(right))
                            x = arrangeSize.Width - element.DesiredSize.Width - right;
                    }
                    double top = Canvas.GetTop(element);
                    if (!double.IsNaN(top))
                    {
                        y = top;
                    }
                    else
                    {
                        double bottom = Canvas.GetBottom(element);
                        if (!double.IsNaN(bottom))
                            y = arrangeSize.Height - element.DesiredSize.Height - bottom;
                    }
                    element.Arrange(new Rect(new Point(x + this.OffsetX, y + this.OffsetY), element.DesiredSize));
                }
            }
            return arrangeSize;
        }
    }
}




다음에는 여기에 Zoom 기능을 넣어보도록 하겠습니다. :)



'Microsoft > WPF' 카테고리의 다른 글

360 파노라마 뷰어  (4) 2014.12.19
Draggable Canvas ver 0.9  (1) 2014.11.17
Expanding Canvas 만들기 2  (0) 2014.11.16
격자 배경 그리기  (0) 2014.11.14
Expanding Canvas 만들기  (2) 2014.11.14