검색결과 리스트
글
편집용 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 (2) | 2014.11.17 |
Expanding Canvas 만들기 2 (0) | 2014.11.16 |
격자 배경 그리기 (0) | 2014.11.14 |
Expanding Canvas 만들기 (2) | 2014.11.14 |
RECENT COMMENT