经常有童鞋在群里面问同样一个问题:如何自定义WF4.0活动的外观。其实一共有两种方式去实现自定义WF4.0活动的外观:一种方式我在以前的博文上实现过,见:WF4.0实战(十一):邮件通知;另外一种方式我将在这里讲述它的实现。故这篇文章中,我将分别用这两种方式去一个最简单的WF4.0自定义活动外观的例子。
第一种方式:使用[Designer]属性。命名空间为:using System.ComponentModel;代码如下:
[Designer(typeof(CustomWriteLineDesigner))] public sealed class CustomWriteLine : CodeActivity { [RequiredArgument] public InArgument<string> Text { get; set; } protected override void Execute(CodeActivityContext context) { Console.WriteLine(context.GetValue(this.Text)); } }
上面代码中的CustomWriteLineDesigner是自定义外观的XAML文件。第一种方式代码还可以这样写:
[("MyActivityDesigner.CustomWriteLineDesigner,MyActivityDesigner")] public sealed class CustomWriteLine : CodeActivity { [RequiredArgument] public InArgument<string> Text { get; set; } protected override void Execute(CodeActivityContext context) { Console.WriteLine(context.GetValue(this.Text)); } }
CustomWriteLineDesigner的代码如下:
<sap:ActivityDesigner x:Class="MyActivityDesigner.CustomWriteLineDesigner" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sadc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation" xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation" xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"> <sap:ActivityDesigner.Resources> <sadc:ArgumentToExpressionConverter x:Key="argConverter"/> </sap:ActivityDesigner.Resources> <sap:ActivityDesigner.Icon> <DrawingBrush> <DrawingBrush.Drawing> <ImageDrawing> <ImageDrawing.Rect> <Rect Location="0,0" Size="16,16" ></Rect> </ImageDrawing.Rect> <ImageDrawing.ImageSource> <BitmapImage UriSource="WriteLine.jpg" ></BitmapImage> </ImageDrawing.ImageSource> </ImageDrawing> </DrawingBrush.Drawing> </DrawingBrush> </sap:ActivityDesigner.Icon> <Grid > <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Text="Text " Padding="0,2,4,2"/> <sapv:ExpressionTextBox MaxLines="1" Grid.Column="1" Width="200" Expression="{Binding Path=ModelItem.Message, Mode=TwoWay, Converter={StaticResource argConverter}, ConverterParameter=In}" OwnerActivity="{Binding Path=ModelItem}" /> </Grid> </sap:ActivityDesigner>
效果:
以上是第一种方式,如果有不清楚的地方可以参考:WF4.0实战(十一):邮件通知
第二种方式:代码关联去实现
上面的方式是硬编码实现的,有些不够灵活,微软内置的活动是采用第二种方式,而不是第一种方式。下面我将一步一步教你如何用第二种方式去实现同样的效果。
新建一ActivityLibrary项目命名为:MyActivityDesignerTwo,新建一个ActivityDesignerLibrary项目命名为MyActivityDesignerTwo.Design。从命名上可以看出,MyActivityDesignerTwo用于实现后台的逻辑代码。MyActivityDesignerTwo.Design用于实现自定义活动的UI。项目结构如下图所示:
其中CustomWriteLineDesigner.xaml代码和第一种方式相同。不同的是多出了一个DesignerMetadata.cs,CustomWriteLine.cs中去掉了Designer属性的代码,去掉了Designer属性的CustomWriteLine代码如下:
public sealed class CustomWriteLine : CodeActivity { [RequiredArgument] public InArgument<string> Text { get; set; } protected override void Execute(CodeActivityContext context) { Console.WriteLine(context.GetValue(this.Text)); } }
DesignerMetadata.cs的代码如下:
public class DesignerMetadata : IRegisterMetadata { /// <summary> /// Register the designer for the write line activity /// </summary> public void Register() { AttributeTableBuilder builder = new AttributeTableBuilder(); Type t = typeof(CustomWriteLine); builder.AddCustomAttributes(t, new DesignerAttribute(typeof(CustomWriteLineDesigner))); MetadataStore.AddAttributeTable(builder.CreateTable()); } }
后台的代码和UI的设计并不在同一个项目中,我们如何将他们关联起来呢?很简单,我们只要将两个项目生成的dll放在同一个目录下面就OK了。我们修改MyActivityDesignerTwo.Design的生成路径。如下图:
新建一个测试的WorkflowConsoleApplication项目,在这个项目中添加MyActivityDesignerTwo引用。
我们将微软内置的WriteLine和刚才定义的活动做个比较,如下图:
你会发现有一个明显不同的地方:我们自定义的活动比微软内置的活动要宽一些。Text属性上我们自定义的WriteLine活动上显示全部的文字:"这个我们自定义的WriteLine活动",而内置的活动隐藏了部分文字没有显示。这一点的是蛮有好处的:在流程设计器上自定义的活动比内置的活动更加直观。
总结:这篇文章教你用两种方式去实现自定义活动的外观。有人可能会问为什么要自定义活动的外观,一个CustomWriteLine就好了呀!自定义活动的外观的好处是使流程设计器上更加直观。只有很直观了,我们的流程设计器才能拿给普通用户使用。
代码:http://files.cnblogs.com/zhuqil/MyActivityDesigner.rar