• 坚持学习WF(5):自定义活动(CustomActivity)


    当WF提供的标准活动不能满足我们的需求的时候,我们就需要定义自己的活动。工作流引擎并不会区别一个活动是WF提供的标准活动还是第三方自定义活动.自定义活动有两种方式,组合方式和继承方式.组合是你从工具箱里拖出你需要的活动将他们组织在一起形成一个新的活动;使用继承的方式我们需要编写一个类,该类可以继承Activity类或其他的类,比如SequenceActivity等.组合的方式比较简单,下面我们就使用继承的方式来自定义一个活动。


    实现逻辑
     

    我现在要完成一个这样的活动,我去银行存钱,当我存钱的时候会有一个友情提示,提示我保护好您的密码,然后如果存钱的数额小于1000就提示说钱太少,不能存,如果大于1000就提示存款成功.

    下面我们就新建一个Activity名字叫CreditActivity,我们在它的属性里将Base类设置为Activity,这个基类已经足够了,然后我们增加一个依赖属性AccountProperty来表示存款数额,代码如下:

    public static DependencyProperty AccountProperty  = System.Workflow.ComponentModel.DependencyProperty.Register( 
               
    "Account"typeof(Int32), typeof(CreditActivity)); 
          
     [Description("存款数额")] 
           [Category(
    "自定义活动示例")] 
           [Browsable(
    true)] 
           [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] 
           
    public Int32 Account 
           { 
               
    get 
               { 
                   
    return ((Int32)(base.GetValue( 
                       CreditActivity.AccountProperty))); 
               } 
               
    set 
               { 
                   
    base.SetValue(CreditActivity.AccountProperty, value); 
               } 
           }

    然后在增加一个依赖事件BeCarefulEvent ,用于当用户存钱的提示它注意保护密码,代码如下:

    public static DependencyProperty BeCarefulEvent = DependencyProperty.Register("BeCareful"typeof(EventHandler<CustomActivityEventArgs>), typeof(CreditActivity)); 
           [DescriptionAttribute(
    "友情提示:注意保护密码")] 
           [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] 
           [BrowsableAttribute(
    true)] 
           [Category(
    "Handlers")] 
           
    public event EventHandler<CustomActivityEventArgs> BeCareful 
           { 
               add 
               { 
                   
    base.AddHandler(CreditActivity.BeCarefulEvent, value); 
               } 
               remove 
               { 
                   
    base.RemoveHandler(CreditActivity.BeCarefulEvent, value); 
               } 
           }

    然后我们要实现我们的逻辑代码,我们需要重写Activity类的Execute方法,并在该方法中引发BeCarefulEvent事件。这个方法返回一个ActivityExecutionStatus,代表当前Activity实例的运行状态的枚举值,Return.base.Execute(executionContext)这个默认的返回ActivityExecutionStatus.Closed. ActivityExecutionContext是提供活动运行环境的相关信息.代码如下

    protected override ActivityExecutionStatus Execute( ActivityExecutionContext executionContext) 
            { 
                CustomActivityEventArgs customActivityEventArgs 
    = new CustomActivityEventArgs(this.Description); 
                
    this.RaiseGenericEvent<CustomActivityEventArgs>(BeCarefulEvent, this, customActivityEventArgs); 
                
    //simulate an account lookup 
                if (Account <= 1000
                { 
                    Console.WriteLine(
    "钱也太少了吧,要大于1000的"); 
                } 
                
    else 
                { 
                    Console.WriteLine(
    "存好了,下回多存点啊"); 
                } 

                
    return base.Execute(executionContext); 
            }

    下面我就在Workflow中设置它的存款数额为600,和BeCarefulEvent事件,如下图:

    3

    (图 一)

    BeCarefulEvent的事件处理程序onBeCareful的代码如下:

    private void onBeCareful(object sender, CaryActivityLibrary.CustomActivityEventArgs e) 
            { 
                Console.WriteLine(e.ActivityDescription
    +":小心保护密码");
                Console.WriteLine()
             }

    现在我们来运行我们的程序:

    4


    提高设计体验

    上面我们只是简单的实现我们的逻辑,但很多时候并不是逻辑是最重要的,我们的设计体验同样重要,下面我们说说自定义活动中怎样才能提高设计的体验。


    自定义活动图标

    不知道你注意到没有,在(图一)中的我们自定义的活动前的图标很好看,这个也是我自己选的,只要下面的一行代码就可以实现:

    [ToolboxBitmap(typeof(CreditActivity), "Test.png")] 
    public partial class CreditActivity : System.Workflow.ComponentModel.Activity{..}

    注意图片的生成操作属性应该设置为“嵌入的资源”,如下图:

    5


    自定义活动主题

    (图一)中活动的主题的样式也是我们自己可以定制的,我们新建一个CreditActivityTheme类,继承自ActivityDesignerTheme,在其构造函数中设置我们想要的样式,代码如下:

    public class CreditActivityTheme : ActivityDesignerTheme 
        { 
            
    public CreditActivityTheme(WorkflowTheme theme) 
                : 
    base(theme) 
            { 
                
    this.BackColorStart = Color.LightSteelBlue; 
                
    this.BackColorEnd = Color.Gainsboro; 
                
    this.BorderStyle = DashStyle.DashDot; 
                
    this.BorderColor = Color.DarkRed; 
                
    this.BackgroundStyle = LinearGradientMode.ForwardDiagonal;            
            } 
        }

    其实Visual Studio本身也提供了强大的主题设计器。


    自定义活动行为

    我们不但可以设置样式,还可以增加以下的行为来用另一种方式设置我们的存款数额,如下图:

    6

    要实现上面的并不难,你需要定义一个CreditActivityDesigner类继承自ActivityDesigner,代码如下:

    [ActivityDesignerTheme(typeof(CreditActivityTheme))] 
        
    public class CreditActivityDesigner : ActivityDesigner 
        { 
            
    protected override System.Collections.ObjectModel.ReadOnlyCollection<DesignerAction> DesignerActions 
            { 
                
    get 
                { 
                    List
    <DesignerAction> list = new List<DesignerAction>(); 
                    
    foreach (DesignerAction temp in base.DesignerActions) 
                    { 
                        list.Add(
    new DesignerAction(this, temp.ActionId, temp.Text)); 
                    } 
                    
    return list.AsReadOnly(); 
                } 
            } 

            
    protected override ActivityDesignerVerbCollection Verbs 
            { 
                
    get 
                { 
                    ActivityDesignerVerbCollection NewVerbs 
    = new ActivityDesignerVerbCollection(); 
                    NewVerbs.AddRange(
    base.Verbs); 
                    ActivityDesignerVerb menu 
    = new ActivityDesignerVerb(this, DesignerVerbGroup.View, "设置存款数额啦"new EventHandler(menu_click)); 
                    NewVerbs.Add(menu); 
                    
    return NewVerbs; 
                } 
            } 
     
            private void menu_click(object sender, EventArgs e) 
            { 
                
    using (CreditActivitySet wf = new CreditActivitySet()) 
                { 
                    
    int v = (int)this.Activity.GetValue(CreditActivity.AccountProperty); 
                    wf.Value 
    = v.ToString(); 
                    wf.ShowDialog(); 
                    
    this.Activity.SetValue(CreditActivity.AccountProperty, Convert.ToInt32(wf.Value)); 
                } 
            } 
        }

    CreditActivitySet 是设置数额的window form。


    自定义活动验证器

    你可能还会记得当你拖动一个CodeActivity的时候,如果你没有设置它的ExecuteCode属性,它会有一个叹号,编译不能通过。下面我们也来实现同样的效果,如果我们没有设置存款数额Account,我们就也出现类似的提示,我们定义一个CreditActivityValidator类继承自ActivityValidator。代码如下:

    public class CreditActivityValidator : ActivityValidator 
        { 
            
    public override ValidationErrorCollection Validate( 
                ValidationManager vManager, 
    object obj) 
            { 
                ValidationErrorCollection errors 
    = base.Validate(vManager, obj); 
                
    if (obj is CreditActivity) 
                { 
                    CreditActivity creditActivity 
    = obj as CreditActivity; 
                    
    if (creditActivity.Parent != null
                    { 
                        
    if (creditActivity.Account == 0
                        { 
                            errors.Add( 
                                ValidationError.GetNotSetValidationError( 
                                    
    "Account")); 
                        } 
                    } 
                } 
                
    return errors; 
            } 
        }

    效果如下图:

    7

    我们是通过以下特性来应用到我们自定义的活动上的 : 

     [ActivityValidator(typeof(CreditActivityValidator))] 
        [Designer(
    typeof(CreditActivityDesigner))] 
        
    public partial class CreditActivity : System.Workflow.ComponentModel.Activity    {}


    定制工具箱行为

    我们还可以定制工具箱行为,就是当我们把一个活动从工具箱拖到工作流设计器上时所做的动作,我另外定义了一个CaryCompositeActivity 活动,继承自 SequenceActivity,这样就可以包含子活动了,当我们把CaryCompositeActivity 拖到工作流设计器时,我们给他添加一些默认的子活动,我们编写了一个CaryCompositeActivityToolboxItem 并继承自ActivityToolboxItem,代码如下:

    [Serializable] 
       
    public class CaryCompositeActivityToolboxItem : ActivityToolboxItem 
       { 
          
     public CaryCompositeActivityToolboxItem() 
               : 
    base() 
           {    } 
           public CaryCompositeActivityToolboxItem( 
               SerializationInfo info, StreamingContext context) 
                   : 
    base(info, context) 
           { } 
           
    protected override IComponent[] CreateComponentsCore(IDesignerHost host) 
           { 
               
    CaryCompositeActivity activity = new CaryCompositeActivity(); 
               
    IfElseActivity ifElse = new IfElseActivity("ifElse1"); 
               
    ifElse.Activities.Add(new IfElseBranchActivity("ifFirstCondition")); 
               ifElse.Activities.Add(
    new IfElseBranchActivity("ifSecondCondition")); 
               ifElse.Activities.Add(
    new IfElseBranchActivity("elseBranch")); 
               activity.Activities.Add(ifElse); 
               
    return new IComponent[] { activity }; 
           } 
       }

    然后我们在写一个类来实现该活动只能添加指定的子活动,我们编写一个类CaryCompositeActivityDesigner 继承自SequentialActivityDesigner,代码如下:

    public class CaryCompositeActivityDesigner : SequentialActivityDesigner 
        { 
            
    private static List<Type> allowedActivityTypes = new List<Type>(); 
            
    static CaryCompositeActivityDesigner() 
            { 
                
    allowedActivityTypes.Add(typeof(IfElseActivity)); 
                allowedActivityTypes.Add(
    typeof(IfElseBranchActivity)); 
                allowedActivityTypes.Add(
    typeof(CodeActivity)); 
            } 
            
    public override bool CanInsertActivities(HitTestInfo insertLocation, 
                ReadOnlyCollection
    <Activity> activitiesToInsert) 
            { 
                
    Boolean result = true
                
    if (activitiesToInsert != null
                { 
                    
    foreach (Activity activity in activitiesToInsert) 
                    { 
                        result 
    = (allowedActivityTypes.Contains(activity.GetType())); 
                        
    if (result == false
                        { 
                            
    break
                        } 
                    } 
                } 
                
    return result; 
            } 
        }


    效果如下图:

    8

    allowedActivityTypes 集合中我们指定了只能添加 IfElseActivity,IfElseBranchActivity,CodeActivity三种活动,但是在它的子活动IfElseBranchActivity中就没有这个限制了,因为IfElseBranchActivity也有自己的设计器。

    代码下载:CaryActivity
    上一篇:坚持学习WF(4):活动(Activity)和依赖属性(DependencyProperty)
    下一篇:坚持学习WF(6):开发可复用的宿主程序

    作者:生鱼片
             
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    XAF 一对多关系<DC翻译博客二>
    XAF 在BOModel中实现接口<DC翻译博客六>
    XPO – (Gary's post)Stored Procedure Support Coming in V2010 Vol 2 Part1
    XAF 如何从Excel复制多个单元格内容到GridView
    XAF 如何实现对选择的单元格显示矩形框和多单元格的复制及粘贴
    XAF 如何扩展应用程序模型<二> 编辑ListView自动保存
    XAF 模型编辑器
    XAF 用代码扩展和自定义应用程序模型
    XAF 翻译领域构件(DC)技术目录
    XPO (Gary's post)Stored Procedure Support coming in V2010 Vol 2 (Part 2)
  • 原文地址:https://www.cnblogs.com/carysun/p/CustomActivity.html
Copyright © 2020-2023  润新知