WPF:从WPF Diagram Designer Part 4学习分组、对齐、排序、序列化和常用功能

  在前面三篇文章中我们介绍了如何给图形设计器增加移动、选择、改变大小面板、缩略图、框线选择和工具箱连接等功能,本篇是这个图形设计器系列的最后一篇,将和大家一起来学习一下如何给图形设计器增加分组、对齐、排序、序列化等功能。

WPF Diagram Designer - Part 4

分组:Group, Ungroup

由于WPF不允许一个对象作为多个其他元素的子对象存在,而当移动父对象时,模板也会Unload导致一些问题,所以在这个系列中对分组的实现方式是:当分组一组元素时,内部生成一个Group,这个Group内部其实也是一个DesignerItem对象,只是IsGroup=true而已,在分组时,内部的对象的ParentID都置为这个Group对象的Id

public interface IGroupable
{
Guid ID {
get; }
Guid ParentID {
get; set; }
bool IsGroup { get; set; }
}

执行分组时的代码如下:

 

private void Group_Executed(object sender, ExecutedRoutedEventArgs e)
{
var items
= from item in this.SelectionService.CurrentSelection.OfType<DesignerItem>()
where item.ParentID == Guid.Empty
select item;

Rect rect
= GetBoundingRectangle(items);

DesignerItem groupItem
= new DesignerItem();
groupItem.IsGroup
= true;
groupItem.Width
= rect.Width;
groupItem.Height
= rect.Height;
Canvas.SetLeft(groupItem, rect.Left);
Canvas.SetTop(groupItem, rect.Top);
Canvas groupCanvas
= new Canvas();
groupItem.Content
= groupCanvas;
Canvas.SetZIndex(groupItem,
this.Children.Count);
this.Children.Add(groupItem);

foreach (DesignerItem item in items)
item.ParentID
= groupItem.ID;

this.SelectionService.SelectItem(groupItem);
}

当我们选择一个分组子对象时,设计器会选择这个分组以及分组的所有子对象

 

 

internal void SelectItem(ISelectable item)
{
this.ClearSelection();
this.AddToSelection(item);
}

internal void AddToSelection(ISelectable item)
{
if (item is IGroupable)
{
List
<IGroupable> groupItems = GetGroupMembers(item as IGroupable);

foreach (ISelectable groupItem in groupItems)
{
groupItem.IsSelected
= true;
CurrentSelection.Add(groupItem);
}
}
else
{
item.IsSelected
= true;
CurrentSelection.Add(item);
}
}

 

 

对齐:Align (Left, Right, Top, Bottom, Centered horizontal, Centered vertical)、Distribute (horizontal, vertical)

 

private void AlignLeft_Executed(object sender, ExecutedRoutedEventArgs e)
{
var selectedItems
= from item in SelectionService.CurrentSelection.OfType<DesignerItem>()
where item.ParentID == Guid.Empty
select item;

if (selectedItems.Count() > 1)
{
double left = Canvas.GetLeft(selectedItems.First());

foreach (DesignerItem item in selectedItems)
{
double delta = left - Canvas.GetLeft(item);
foreach (DesignerItem di in SelectionService.GetGroupMembers(item))
{
Canvas.SetLeft(di, Canvas.GetLeft(di)
+ delta);
}
}
}
}

 

private void AlignHorizontalCenters_Executed(object sender, ExecutedRoutedEventArgs e)
{
var selectedItems
= from item in SelectionService.CurrentSelection.OfType<DesignerItem>()
where item.ParentID == Guid.Empty
select item;

if (selectedItems.Count() > 1)
{
double center = Canvas.GetLeft(selectedItems.First()) + selectedItems.First().Width / 2;

foreach (DesignerItem item in selectedItems)
{
double delta = center - (Canvas.GetLeft(item) + item.Width / 2);
foreach (DesignerItem di in SelectionService.GetGroupMembers(item))
{
Canvas.SetLeft(di, Canvas.GetLeft(di)
+ delta);
}
}
}
}

 

 

排序:Order (Bring forward, Bring to top, Send backward, Send to back)

 

private void BringForward_Executed(object sender, ExecutedRoutedEventArgs e)
{
List
<UIElement> ordered = (from item in SelectionService.CurrentSelection
orderby Canvas.GetZIndex(item
as UIElement) descending
select item
as UIElement).ToList();

int count = this.Children.Count;

for (int i = 0; i < ordered.Count; i++)
{
int currentIndex = Canvas.GetZIndex(ordered[i]);
int newIndex = Math.Min(count - 1 - i, currentIndex + 1);
if (currentIndex != newIndex)
{
Canvas.SetZIndex(ordered[i], newIndex);
IEnumerable
<UIElement> it = this.Children.OfType<UIElement>().Where(item => Canvas.GetZIndex(item) == newIndex);

foreach (UIElement elm in it)
{
if (elm != ordered[i])
{
Canvas.SetZIndex(elm, currentIndex);
break;
}
}
}
}
}

序列化:Open, Save

使用XML保存,代码如下:

XElement serializedItems = new XElement("DesignerItems",
from item
in designerItems
let contentXaml
= XamlWriter.Save(((DesignerItem)item).Content)
select
new XElement("DesignerItem",
new XElement("Left", Canvas.GetLeft(item)),
new XElement("Top", Canvas.GetTop(item)),
new XElement("Width", item.Width),
new XElement("Height", item.Height),
new XElement("ID", item.ID),
new XElement("zIndex", Canvas.GetZIndex(item)),
new XElement("IsGroup", item.IsGroup),
new XElement("ParentID", item.ParentID),
new XElement("Content", contentXaml)
)
);

读取的时候需要建立Connection

 

private void Open_Executed(object sender, ExecutedRoutedEventArgs e)
{
       ... 
foreach (XElement connectionXML in connectionsXML)
{
Guid sourceID
= new Guid(connectionXML.Element("SourceID").Value);
Guid sinkID
= new Guid(connectionXML.Element("SinkID").Value);

String sourceConnectorName
= connectionXML.Element("SourceConnectorName").Value;
String sinkConnectorName
= connectionXML.Element("SinkConnectorName").Value;

Connector sourceConnector
= GetConnector(sourceID, sourceConnectorName);
Connector sinkConnector
= GetConnector(sinkID, sinkConnectorName);

Connection connection
= new Connection(sourceConnector, sinkConnector);
Canvas.SetZIndex(connection, Int32.Parse(connectionXML.Element(
"zIndex").Value));
this.Children.Add(connection);
}
}

常用功能:Cut, Copy, Paste, Delete,Print

private void Cut_Executed(object sender, ExecutedRoutedEventArgs e)
{
CopyCurrentSelection();
DeleteCurrentSelection();
}

 

private void Print_Executed(object sender, ExecutedRoutedEventArgs e)
{
SelectionService.ClearSelection();

PrintDialog printDialog
= new PrintDialog();

if (true == printDialog.ShowDialog())
{
printDialog.PrintVisual(
this, "WPF Diagram");
}
}

 

 

欢迎转载,转载请注明:转载自周金根 [ http://zhoujg.cnblogs.com/ ]

posted on 2010-08-19 15:03  周 金根  阅读(6203)  评论(6编辑  收藏  举报

导航