검색결과 리스트
글
Expanding Canvas 만들기 2
목차
지난 포스팅(http://crystalcube.co.kr/154) 에서 Expanding Canvas 를 만들어 보았습니다. 이 Canvas 는 Child 가 우측 또는 하단으로 이동할 경우에만 확장이 됩니다. 상단이나 좌측으로 이동할 때는 확장이 되지 않지요. 이 단점을 보완한, 무한 확장 캔버스를 만들어 보려고 합니다.
개요
앞서 방식대로 MeasureOverride 를 이용합니다. 그리고 추가적으로 ArrangeOverride 로 사용해야 합니다. 이 메소드에서 child 들의 위치를 새로 잡아줄 필요가 있기 때문입니다.
child 를 가장 좌상단으로 이동한다고 가정해 보죠. 0,0 의 위치에서 더 좌측으로 이동하면 화면상으로 어떻게 될까요? 캔버스는 확장 된다고 하더라도, 화면상에서의 child 좌표는 여전히 0,0 일 것입니다.
만약 A 랑 B 가 있다고 해 봅시다. A 는 앞서 설명한대로 0,0 에 위치합니다. 그리고 B가 10,10 에 위치합니다. 이 경우 A 를 좌상단으로 5,5 만큼 더 이동하면 어떻게 될까요? A 는 여전히 화면상에서 0,0 위치에 있겠지요. 그러나 B 15,15 가 될 것입니다.
이런 부분들을 ArrangeOverride 에서 처리하려고 합니다.
코드를 보면, child 의 갯수가 1개인 경우 별도로 처리해 주는 코드들이 보입니다. 이 부분은 child 가 1개만 있는 경우 동작이 조금 다르기 때문입니다. 이 부분을 없애고 테스트 해 보시면 무슨 이야기인지 알게 되실겁니다. :)
다소 코드가 좀 지저분하네요 =_=;;
보시다시피, 약간 어색한 부분이 있습니다. 이것은 스크롤바의 스크롤이 마우스를 따라가지 않기 때문인데요.
이 부분이 어색하지 않게 하려면, 스크롤바를 수정해 주어야 합니다. 다음에 시간이 날때, 해당 부분 관련해서 포스팅 하도록 하겠습니다.
Behavior 관련 코드는 지난 포스팅을 참고하시기 바랍니다.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using MS.Internal;
using SW.Common.Extensions;
namespace SW.Common.Controls
{
public class ExpandingCanvas : Canvas
{
static ExpandingCanvas()
{
if(DesignerProperties.GetIsInDesignMode(new DependencyObject()) == false)
{
Canvas.LeftProperty.OverrideMetadata(typeof(UIElement), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsParentMeasure));
Canvas.TopProperty.OverrideMetadata(typeof(UIElement), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsParentMeasure));
Canvas.RightProperty.OverrideMetadata(typeof(UIElement), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsParentMeasure));
Canvas.BottomProperty.OverrideMetadata(typeof(UIElement), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsParentMeasure));
}
DefaultStyleKeyProperty.OverrideMetadata(typeof(ExpandingCanvas), new FrameworkPropertyMetadata(typeof(ExpandingCanvas)));
}
protected override Size MeasureOverride(Size constraint)
{
List<FrameworkElement> children = this.FindVisualDescendants<FrameworkElement>().ToList();
if (children.Count <= 0) { return base.MeasureOverride(constraint); }
double right = 0.0;
double bottom = 0.0;
if (children.Count == 1 && children[0] != null)
{
Point point = new Point(Canvas.GetLeft(children[0]), Canvas.GetTop(children[0]));
point.X = double.IsNaN(point.X) ? 0.0 : point.X;
point.Y = double.IsNaN(point.Y) ? 0.0 : point.Y;
right = Math.Abs(point.X) + children[0].ActualWidth;
bottom = Math.Abs(point.Y) + children[0].ActualHeight;
}
else
{
foreach (FrameworkElement child in children)
{
Point p = child.TranslatePoint(new Point(child.ActualWidth, child.ActualHeight), this);
right = Math.Max(right, p.X);
bottom = Math.Max(bottom, p.Y);
}
}
if (right <= 0.0 || bottom <= 0.0) { return base.MeasureOverride(constraint); }
return new Size(right, bottom);
}
protected override Size ArrangeOverride(Size arrangeSize)
{
double minX = double.MaxValue;
double minY = double.MaxValue;
if (this.InternalChildren.Count <= 1) {
minX = minY = 0.0;
} else {
foreach (UIElement element in InternalChildren) {
minX = Math.Min(Canvas.GetLeft(element), minX);
minY = Math.Min(Canvas.GetTop(element), minY);
}
minX = double.IsNaN(minX) ? 0.0 : minX;
minY = double.IsNaN(minY) ? 0.0 : minY;
}
if (this.InternalChildren.Count == 1 && this.InternalChildren[0] != null)
{
UIElement element = this.InternalChildren[0];
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 < 0.0 ? 0.0 : x), (y < 0.0 ? 0.0 : y)), element.DesiredSize));
}
}
else
{
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 - minX, y - minY), element.DesiredSize));
}
}
}
return arrangeSize;
}
}
}
'Microsoft > WPF' 카테고리의 다른 글
Draggable Canvas ver 0.9 (2) | 2014.11.17 |
---|---|
편집용 Canvas 만들기 (0) | 2014.11.16 |
격자 배경 그리기 (0) | 2014.11.14 |
Expanding Canvas 만들기 (2) | 2014.11.14 |
Drag Canvas 만들기 (0) | 2014.11.13 |
RECENT COMMENT