WPF:从WPF Diagram Designer Part 2学习面板、缩略图、框线选择和工具箱

本文是WPF Diagram Designer系列的第二部分,详细讲解了设计面板的可变大小和滚动、缩略图功能的实现、框线选择(Rubberband selection)以及工具箱(Toolbox)的拖放操作。通过实例代码,阐述了如何在WPF中创建高效的设计界面,并解决了性能和交互问题。
摘要由CSDN通过智能技术生成

  在从WPF Diagram Designer Part 1学习控件模板、移动、改变大小和旋转中介绍了图形设计器的移动、大小和旋转等功能的实现,本篇继续第二部分,学习设计面板、缩略图、框线旋转和工具箱等功能的实现。 

WPF Diagram Designer - Part 2

2009112317371418.png

设计面板(Designer Canvas :variable size, scrollable)

  在从WPF Diagram Designer Part 1学习控件模板、移动、改变大小和旋转中的示例出来的设计器,当把设计对象拖动到DesignerCanvas边界外时,因为DesignerCanvas没有滚动条,我们会发现再也找不到这个对象了。想到解决最简单的办法就是给DesignerCanvas添加一个ScrollViewer,但是这个办法解决不了这个问题,因为当拖动到Canvas之外时,并不会出发Canvas的大小发生变化,所以仍旧没有滚动条,为了解决这个问题,我们则必须在设计对象移动和改变大小时去调整Canvas的大小。

  WPF控件提供一个MeassureOverride允许控件计算希望的大小,再返回WPF框架来进行布局。我们可以在DesignerCanvas中重载这个方法来解决上面所说的问题,重载方法如下:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
protected override Size MeasureOverride(Size constraint)
{
Size size
= new Size();
foreach (UIElement element in base .Children)
{
double left = Canvas.GetLeft(element);
double top = Canvas.GetTop(element);
left
= double .IsNaN(left) ? 0 : left;
top
= double .IsNaN(top) ? 0 : top;

// measure desired size for each child
element.Measure(constraint);

Size desiredSize
= element.DesiredSize;
if ( ! double .IsNaN(desiredSize.Width) && ! double .IsNaN(desiredSize.Height))
{
size.Width
= Math.Max(size.Width, left + desiredSize.Width);
size.Height
= Math.Max(size.Height, top + desiredSize.Height);
}
}
// for aesthetic reasons add extra points
size.Width += 10 ;
size.Height
+= 10 ;
return size;
}

  注:当设计对象很多时,我猜测可能会有性能问题。在ZoomableApplication2: A Million Items介绍了一个可以显示百万级对象的示例,不知道能否解决这个性能问题,先把这个在这里留个足迹,以便以后可以找到

缩略图(Zoombox)

2010081714102924.png

缩略图如上图所示,使用ZoomBox时需要传入一个  ScrollViewer="{Binding ElementName=DesignerScrollViewer}",以便可以通过移动缩略图上的选择框来移动DesignerCanvas

代码文件【ZoomBox.cs】如下:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
public class ZoomBox : Control
{
private Thumb zoomThumb;
private Canvas zoomCanvas;
private Slider zoomSlider;
private ScaleTransform scaleTransform;
private DesignerCanvas designerCanvas;

public ScrollViewer ScrollViewer
{
get { return (ScrollViewer)GetValue(ScrollViewerProperty); }
set { SetValue(ScrollViewerProperty, value); }
}

public static readonly DependencyProperty ScrollViewerProperty =
DependencyProperty.Register(
" ScrollViewer " , typeof (ScrollViewer), typeof (ZoomBox));

public override void OnApplyTemplate()
{
base .OnApplyTemplate();

if ( this .ScrollViewer == null )
return ;

this .designerCanvas = this .ScrollViewer.Content as DesignerCanvas;
if ( this .designerCanvas == null )
throw new Exception( " DesignerCanvas must not be null! " );

this .zoomThumb = Template.FindName( " PART_ZoomThumb " , this ) as Thumb;
if ( this .zoomThumb == null )
throw new Exception( " PART_ZoomThumb template is missing! " );

this .zoomCanvas = Template.FindName( " PART_ZoomCanvas " , this ) as Canvas;
if ( this .zoomCanvas == null )
throw new Exception( " PART_ZoomCanvas template is missing! " );

this .zoomSlider = Template.FindName( " PART_ZoomSlider " , this ) as Slider;
if ( this .zoomSlider == null )
throw new Exception( " PART_ZoomSlider template is missing! " );

this .designerCanvas.LayoutUpdated += new EventHandler( this .DesignerCanvas_LayoutUpdated);

this .zoomThumb.DragDelta += new DragDeltaEventHandler( this .Thumb_DragDelta);

this .zoomSlider.ValueChanged += new RoutedPropertyChangedEventHandler < double > ( this .ZoomSlider_ValueChanged);

this .scaleTransform = new ScaleTransform();
this .designerCanvas.LayoutTransform = this .scaleTransform;
}

private void ZoomSlider_ValueChanged( object sender, RoutedPropertyChangedEventArgs < double > e)
{
double scale = e.NewValue / e.OldValue;

double halfViewportHeight = this .ScrollViewer.ViewportHeight / 2 ;
double newVerticalOffset = (( this .ScrollViewer.VerticalOffset + halfViewportHeight) * scale - halfViewportHeight);

double halfViewportWidth = this .ScrollViewer.ViewportWidth / 2 ;
double newHorizontalOffset = (( this .ScrollViewer.HorizontalOffset + halfViewportWidth) * scale - halfViewportWidth);

this .scaleTransform.ScaleX *= scale;
this .scaleTransform.ScaleY *= scale;

this .ScrollViewer.ScrollToHorizontalOffset(newHorizontalOffset);
this .ScrollViewer.ScrollToVerticalOffset(newVerticalOffset);
}

private void Thumb_DragDelta( object sender, DragDeltaEventArgs e)
{
double scale, xOffset, yOffset;
this .InvalidateScale( out scale, out xOffset,
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值