在前面三篇文章中我们介绍了如何给图形设计器增加及和等功能,本篇是这个图形设计器系列的最后一篇,将和大家一起来学习一下如何给图形设计器增加分组、对齐、排序、序列化等功能。
分组: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 " ); } }
本文转自 jingen_zhou 51CTO博客,原文链接:http://blog.51cto.com/zhoujg/517448,如需转载请自行联系原作者