原文地址:http://www.cnblogs.com/llxxbb/archive/2006/12/11/RehostingWorkflowDesigner.html
有关Hosting Workflow Designers的话题在ms-help://MS.MSSDK.1033/MS.NETFX30SDK.1033/WF_GettingStarted/html/185cc192-b19d
The primary classes that you must use when you host a workflow designer are as follows:
· The .NET DesignSurface class, which implements what the user perceives as a designer by providing a completely self-contained design surface.
· The WorkflowView class, which displays a visual representation of a workflow that is described in workflow markup.
· The WorkflowDesignerLoader class, which supports custom loading of a workflow designer and workflow designer components.
· The WorkflowDesignerMessageFilter class, which creates message filters to respond to workflow designer events, such as drag operations, layout and paint operations, and other designer events.
并且提供了一个例子Basic Designer Hosting。我们可以照这个例子可以加载一个Sequential Workflow的设计器,当然这个例子是非常简单了。这也被很多人所引用和翻译,根据我在开发试验过程中的验证,我想阐述一下我对Hosting Workflow Designers的一些看法。
DesignSurface:对设计时进行支持的一个重要的类,虽然名字中有Surface一词,但他去不能显示。他所侧重的是“服务”的添加与获取。这些服务如:工具箱、菜单、设计时的宿主、类型描述、选择等。
WorkflowView:这个类不像Windows SDK Documentation上说的那样,它不是必须的。这里所说的不是必须的是指不用我们去显示的去“new”一个出来,如果不用消息过滤的话,甚至连“WorkflowView”这个类名也不用。在DesignSurface中有一个View属性,这个属性就是我们的设计器的可视的界面。我们只要把它放在我们自己的容器上就可以了。
WorkflowDesignerLoader:没有它我们照样可以把设计器显示出来,并且可以用代码对设计器里的内容进行设计。但如果想要Workflow 设计器直接响应用户的鼠标和键盘事件,则必须使用它。还有如果想要对设计的东西进行持久化的话,则最好在这里面进行。
WorkflowDesignerMessageFilter:如果想要禁止用户对Workflow设计器的某些交互事件,或做一些特殊的事情,则可以使用这个类;且此类是和WorkflowDesignerLoader一块使用的,否则不起作用。也就是说通常情况下我们可以不关心这个类,这个类是可选的而不是必须的。
如果想做出像VS集成环境那样的设计器,还有许多的工作要做。比如工具箱、属性窗口等。这里面还有很多的技术点,尤其是支持鼠标从工具箱上拖活动到设计器上,让我走了不少的弯路,但最终还是实现了。因为工作烦忙的原因,等我有时间再写吧。
(二)
原文地址:http://www.cnblogs.com/llxxbb/archive/2006/12/25/DragActivityToRehostedDesigner.html
要将活动从工具箱拖放到设计器上去,则在自定义的工具箱中要实现接口IToolboxService。要自己实现这个比较大的接口难度比较大,可心直接从 ToolboxService 类进行继承。这个类提供对 IToolboxService 接口的默认实现。这些在网上都有很多的例子,这里就不多说了。
接下来就可以用类似下面的代码来将工具箱添加到设计器中的服务里面了。
MySurface.AddService(typeof(IToolboxService), MyToolBox);
其中MySurface指的是表面设计器或表面管理器实例,MyToolBox则是自定义工具箱的实例。
完成这些后设计器就可以利用拖放的功能接受来自工具箱中的控件了。我试过,Form设计器和UserControl设计器都可以接受拖放。但工作流设计器却还是不可以的。为此我查阅过相关的资料在Windows Workflow Foundation - MSDN Forums中找到一篇关于“Designer and the Toolbox”的文章(http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=95682&SiteID=1)。其中有下面的描述:
In drag/drop operations, the workflow designer expects a DataObject[ 13 ] filled with two custom data BLOBS “CF_WINOEDESIGNERCOMPONENTS” and “CF_WINOEDESIGNERCOMPONENTSSTATE”. The code to fill in these values is quite long and Arjun was able to send me those lines though the rest of the sample isn’t ready yet. CF_WINOEDESIGNERCOMPONENTS is a memory stream filled in with the entire activity graph serialized into binary using XomlComponentSerializationService. CF_WINOEDESIGNERCOMPONENTSSTATE is also a memory stream, which contains the state for each designer of each activity in the graph.
并且在其后还有下面的内容:
Hopefully we will see the Microsoft sample soon, but I sincerely hope many of these steps are simplified into a helper component that can be released soon and included in the next beta cycle.
看到希望是渺茫了!
后来又找到下面文章“Windows Workflow Foundation: Everything About Re-Hosting the Workflow Designer”(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlong/html/WFDsgnRehst.asp),在这里面工具箱对CF_WINOEDESIGNERCOMPONENTS进行了实现(分别在序列化方法和反序列化方法中)。虽然如此,这两个方法并没有在运行时进行调用,然而这个例子却真的能够实现活动的拖放,这让我感到迷惑。
那么究竟是什么影响着拖放的关键所在?我仔细的研究了一下这个例子的MouseDown事件,除了一行语句外没有什么特别的事情,
ToolboxItem toolboxItem = ToolboxService.GetToolboxItem(selectedItem.ComponentClass);对正是ToolboxService.GetToolboxItem方法起了关键作用。在调用IToolboxService的SerializeToolboxItem方法时所传递的参数必须从ToolboxService.GetToolboxItem进行返回,而不能通过下面的方式将CurToolItem作为参数。
Type typ = typeof(CodeActivity);
_CurToolItem = new ToolboxItem(typ);
否则拖放操作就会泡汤
(三)
原文地址:http://www.cnblogs.com/llxxbb/archive/2006/12/28/RehostWWFDesigner3.html
本文的主要目的为:在Rehost WWF Designer后,我希望用户看到的是更为专用化的设计器而不是由微软所提供的缺省的E文提示(至少当前版本是这样子的)。因为工作繁忙,本文所指的外观设计并不全面,只局限于标题和文字,还希望大家原谅。不过就一般的应用而言,我想这些能满足大部分需求。
让我们先来了解一下定制外观的基础,当我们想对某一个活动的外观进行定制时,我们必须为其指定一个自定义的Designer, 因为其中的外观属性基本上是Protected属性的。所有的外观特性都由Designer来提供,如活动中心的提示信息,标题中的文本,边框,底色等等。其中的一些是在Designer中指定ActivityDesignerThemeAttribute属性来实现的。将Designer应用到我们自定义的活动上面去,我们就可以看到这些效果了。示例如下:
[Designer(typeof(MySequentialWorkflowActivityDesigner), typeof(IRootDesigner))]
public class MySequentialWorkFlowActivity : SequentialWorkflowActivity
{
}
其中MySequentialWorkFlowActivity为我们自定义的活动。MySequentialWorkflowActivityDesigner为我们自定义的设计器(应该称之为外观设计器可能更好一些)。IRootDesigner则说明这是一个根控件。对于WWF来讲这是我们的设计器中的第一个控件。如果不是根控件,如CodeActivity则应将其替换为IDesigner。
进入我们的正题,
现在让我们来改变SequentialWorkflowActivit的标题和帮助文本。
从SequentialWorkflowRootDesigner继承一个自定义的Designer。
重载并实现下面的方法。
// 改变帮助提示信息
protected override string HelpText
{
get{return Res.WF_HelpText; }
set{base.HelpText = value; }
}
// 改变标题
protected override SequentialWorkflowHeaderFooter Header
{
get
{
base.Header.Text = Res.WF_Text;
return base.Header;
}
}
注意:在Designer中有一个Text属性,不能将它作为标题进行使用!
其它活动的Designer可以通过继承ActivityDesigner来实现。一般情况下自定义活动的名字被显示在活动的中心位置。如果想拥有活动的英文名字,但显示是汉字内容则可以通过实现其Designer中的Text属性来解决,这里就不多做说明了。
(四)
原文地址 :http://www.cnblogs.com/llxxbb/archive/2007/01/12/ChangeRuntimeAppearanceOfWWFDesigner.html
最近在运用工作流设计器时遇到一个问题,客户在选择工作流中的一个活动时需要高亮显示,而不仅是有选择句柄。问题好像很简单,活动的颜色控制最简单的控制方式是由ActivityDesignerTheme来控制的,当然你也可以在Designer中的OnPaint方法中进行手工绘制,但我是不喜欢这样去劳心的:)。
在Designer.的OnPaint方法中,我对Designer的样式进行了操作。Designer的DesignerTheme属性可以直接取得设计样式,然后我对其中的BackColorStart和BackColorEnd进行了赋值,在满怀期待中运行……。但系统给出了一个异常,内容为:“Theme properties can only be changed in the Theme Configuration Dialog.”;那么创建一个新的Theme给Designer如何?答案是不可以的,因为DesignerTheme属性是只读的。这种利用Theme来改变外观的方式好像是行不通的,但我并没有放弃。
我仔细看了一下Theme中的成员列表,发现了GetBackgroundBrush方法,这将得到一个System.Drawing.Drawing2D.LinearGradientBrush类型的刷子。可不可以对刷子的颜色进行改变呢?我做了一下尝试,对刷子的LinearColors进行了赋值,运行。结果是令人兴奋的!
另一个还未解决的问题是判定活动是否被选择,这个很简单,在Designer中有个属性IsSelected,在Designer中的OnPaint中判断一下就可以了。
总结,如果只是想在运行时改变样式,不能直接改变样式所提供的样式属性进行变更,我们可以通过获取样式提供的笔、刷子等与绘图相关的更底层的对象,然后对其进行相应的设置就可以了。对于字体而言,则需要在派生的Theme中对Font进行重新实现。因为工作忙碌的原因,其它的就自己试吧。