WPF中的图表设计器 – 4 (译)

简介:

[原文地址] http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part4.aspx 
[原文作者] 
sukram

  • Part 1 - 在Canvas中移动、缩放或者旋转任何类型的对象
  • Part 2 - Toolbox, drag & drop, rubberband selection
  • Part 3 - Connecting items

介绍

在这篇文章中,我添加下面的命令:

  • OpenSave
  • CutCopyPasteDelete
  • Print
  • GroupUngroup
  • Align (LeftRightTopBottomCentered horizontalCentered vertical)
  • Distribute (horizontalvertical)
  • Order (Bring forwardBring to topSend backwardSend to back)

   注意:我将仅仅支持.NET 3.5平台下面的Visual Studio 8.0!

命令

   我将直接使用WPF命令,就像在WPF SDK文档中描述一样,无需额外的基础设施。

分组

   我的第一个分组的方法是将一个DesignerItem对象作为一个分组的容器使用。因此,创建一个DesignerItem类的新实例对象,这个实例对象的content是一个Canvas对象。在这个canvas中,我计划放置进行分组的DesignerItem。不过,在我把item放在用于分组的canvas上之前,我必须从DesignerCanvas移除他们,这因为WPF中的元素不能同时是两个元素的子元素。否者,如果您去尝试,您将得到InvalidOperationException异常,并收到下面的异常消息:

" Specified element is already the logical child of another element. 
Disconnect it first. "

   所以,我们从DesignerCanvas上移除Item ,然后将它添加到GroupCanvas上。现在有趣的是理解WPF幕后所做的工作:当我从画布上移除的Item时,Item的模板被卸下,当我把它添加到GroupCanvas上时,一个新的模板又会被加载。现在,你还记得上一篇文章中我如何连接DesignerItems会的吗?在那里,我通过Connector去实现连接Item,Connector是被连接的DesignerItem的模板的一部分。一旦我们从DesignerCanvas删除Item,它的模版也将消失。你看到问题吗?我是通过他们的模板连接DesignerItem的,所以DesignerItem本身根本没有存在有关Connection的信息。所有Connection的相关信息是与DesignerItem的模板孤立的。

    想象一下,一个数据库关系图中,DesignerItem的content是一个数据库表。该表将永远不会认可与其他表的关系。一个解决办法是建立一个信息隧道,信息从DesignerItem的模板传到DesignerItem,再传到table。 更好的解决办法是重新设计应用程序和划整为零,如划分为:

 

  • Template (view)
  • Designer item (view model)
  • Database table (model)

     

       我在这篇文章中间将不会重新设计代码。相反,直到文章的结尾,我将使用'view-only-approach'。使用越难,好的解决方法就越有希望。(我将会在以后的文章中涉及一些支持模型设计的文章)。

       所以让我们继续,另外一种对DesignerItem分组方法,是使用下面的接口:

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

     

       这个观点是用已经实现了IGroupable接口的DesignerItem类,成为分组结构的一部分。它如下工作:

    • 创建一个新的DesignerItem对象,它有一个唯一的ID和一个设置为true的IsGroup属性。
    • 对于每一个组成员,设置他的ParentID为父亲group的ID。

       这个非常简单,当真正地修改Item(Select, Move, Resize, Copy, ...)的时候,它才真正的起作用。对于每个操作,我们都要考虑item的分组的状态,听起来有很多工作要做。但是使用了ling,就没那么难了。因此,我们将大部分工作放在SelectionService中去实现。

       注意:Connection类没有实现IGroupable接口。所以它不是分组的直接部分。但间接地:一个connection 总是附加到一个item上。这使我可以灵活地重连/连接item。无论他们是否是一个分组的成员。

    Save

       为了保存一个图表,我选择使用XML和XAML的组合。对于DesignerItem相关的数据,我使用XML,content将序列化为XAML。在这里,请注意序列化DesignerItem的content为XAML仅仅保留视觉效果。因此,这是短期内唯一的解决办法。要创建XML文件,我使用LINQ。由于这是我第一次使用LINQ来做,使用它不要指望它是必要的“正确”的方法。

       下面是一个例子,我是如何序列DesignerItem: 

     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)
                                          )
                               );

    在让关键字允许您在一个变量中存储在一个子表达式的结果,这个变量可以在随后的表达式中使用。在这里,我使用此功能将序列化的content保存在contentXaml变量,我用下面几行代码。最后,我将使用XElement类的Save方法来存储基本XML树:

 

 XElement.Save(fileName)

Open

    当我们从XML文件加载一个图表的时候,我们必须从加载DesignerItem开始,因为我们需要他们的connector来创建connection。我们了解到,connector是该item模板的一部分。在我们继续以前,DesignerItem必须加载他的模板。幸运的是,控件的类提供了一个ApplyTemplate()方法。它强迫WPF布局系统加载控件模板,以便它的部分能被引用。

    在前面的一篇文章中,我提供一个自定义ConnectorDecorator模板的机制,它允许你在DesignerItem的周围自由地放置connector 。这种解决办法,在DesignerItem的Loaded事件之后, 应用自定义模板。该DesignerItem在屏幕上可见之前,而不会激发该事件。在该命令已经结束之前,屏幕不能重绘。因此,唯一的方法是将在打开命令中明确设置ConnectorDecorator自定义模板,看到SetConnectorDecoratorTemplate(item)的方法。

 注意:当定义定制的connector时,必须设置的x:Name属性。一个connection使用名字来确定其来源和接收的connector。

 

 <s:Connector x:Name="Left" Orientation="Left" 
    VerticalAlignment
="Center" HorizontalAlignment="Left"/>

 

Copy, Paste, Delete, Cut

   复制和粘贴命令的工作类似于打开和保存命令,但它们只适用于所选的item ,他们读写序列化的content到剪贴板。 删除命令只是从designer canvas所有的子集中删除选定item,最后剪切命令是一个复制和删除命令的组合。

Align, Distribute

   这些命令,没有太多的话要说,首先,除了在Align中第一个被选中的item是参考item (也称为主选择item)。这仅仅当你使用 LeftMouseButton + Ctrl, 或者LeftMouseButton + Shift选择item,而不是你去用rubberband选择。

Order

   这个Panel类提供了一个名字为ZIndex的附加的的属性。它定义了z-plane子元素的显示的顺序。所以我们只需要更改该属性将item向前或向后。

     WPF中的图表设计器一共有四篇文章,前面三篇已经由WizRay翻译,你也可以在我的博客上找到,这是第四篇。希望这些对想实现自己WPF流程设计器和表单设计器的朋友有所帮助。(红色译者注)






本文转自麒麟博客园博客,原文链接:http://www.cnblogs.com/zhuqil/archive/2009/12/24/1631726.html,如需转载请自行联系原作者

相关文章
|
前端开发 C#
WPF 曲线图表控件(自制)(一)
原文:WPF 曲线图表控件(自制)(一) 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/koloumi/article/details/77509283 由于公司需要所以自写了一个简单的曲线图表控件,在此分享。
1914 0
|
C# 前端开发
WPF - 图形设计器(Diagram Designer)
原文:WPF - 图形设计器(Diagram Designer)   OpenExpressApp计划中包括建模工具,计划是采用MetaEdit+模型来作为元模型,使用codeproject的《WPF Diagram Designer》一系列文章来做为设计器实现参考,本篇介绍一下codeprojcet的这四个文章,推荐给对图形设计器感兴趣的人去看看,通过WPF的模板功能和其他功能可以很方便的设计出图形编辑器。
3359 0
|
Web App开发 数据可视化 前端开发
WPF调用 ECharts 显示图表
WPF调用 ECharts 显示图表
WPF调用 ECharts 显示图表
|
移动开发 C# HTML5
WPF实现图表绘制
WPF实现图表绘制
WPF实现图表绘制
|
前端开发 C#
WPF 自定义的图表(适用大量数据绘制)下
原文:WPF 自定义的图表(适用大量数据绘制)下 上一篇文章中讲了WPF中自定义绘制大量数据的图标,思路是先将其绘制在内存,然后一次性加载到界面,在后续的调试过程中,发现当数据量到达10W时,移动鼠标显示数据有明显的延迟。
1394 0
|
C#
WPF设计の画刷(Brush)
原文:WPF设计の画刷(Brush)   一、什么是画刷         画刷是是一种渲染方式,用于填充图形形状,如矩形、椭圆、扇形、多边形和封闭路径。在GDI+中,画刷分为以下几种:SolidBrush,TextureBrush,HatchBrush,LinearGradientBrush和PathGradientBrush。
1031 0
|
C#
wpf控件设计时支持(2)
原文:wpf控件设计时支持(2) 这篇介绍在wpf设计时集合项属性添加项的定义和自定义控件右键菜单的方法 集合项属性设计时支持   1.为集合属性设计器识别具体项类型 wpf设计器允许定义集合项的类型,如新发布的WPF的DataGrid控件,其中的Columns包括一下几种类型,Columns集合属性是以下几个类型的抽象类集合.
1071 0
|
C# .NET 开发框架
wpf控件设计时支持(1)
原文:wpf控件设计时支持(1)    这部分内容几乎是大家忽略的内容,我想还是来介绍一下. 本篇源码下载 1.属性元数据 在vs IDE中,在asp.net,winfrom等开发环境下,右侧的PropertyGrid属性面板,会对属性进行分类,这有利于了解控件属性的用途.
993 0
|
C# 容器 数据可视化
wpf控件设计时支持(3)
原文:wpf控件设计时支持(3)     wpf设计时调试 编辑模型 装饰器 1.wpf设计时调试   为了更好的了解wpf设计时框架,那么调试则非常重要,通过以下配置可以调试控件的设计时代码 (1)将启动项目配置成外部的visual studio ide启动程序devenv.
1063 0
|
数据可视化 C# 容器
WPF 多线程 UI:设计一个异步加载 UI 的容器
原文 WPF 多线程 UI:设计一个异步加载 UI 的容器 对于 WPF 程序,如果你有某一个 UI 控件非常复杂,很有可能会卡住主 UI,给用户软件很卡的感受。但如果此时能有一个加载动画,那么就不会感受到那么卡顿了。
1596 0