zoukankan      html  css  js  c++  java
  • 轻松构建自定义WF设计器

      最近在研究WF4.0,需要在4.0的基础上将业务逻辑与Activities进行一些封装,所以就做了一个设计工具,那么自会有人问,为什么不直接在VS上进行操作了,为什么要自己再造轮子,呵呵,理由有二:一是此工具是直接面对一线开发人员,二是做工具同时需要提供封装后WF的接口,供开发人员调用(这里会有一个WF解析引擎)。好,不多废话,直接进入主题。

      一:熟悉基本类。

        1.WorkflowDesigner 类,提供设计器画布,该设计器画布呈现工作流模型正在设计时的可视表示形式。

         在此类中我们会用到:

         public ContextMenu ContextMenu { get; }

                  ContextMenu 继承MenuBase,表示一个弹出菜单,该弹出菜单使控件能够公开特定于该控件的上下文的功能。

         public UIElement PropertyInspectorView { get; } 返回属性框

         public string Text { get; set; } 返回当前工作流实例的Xaml代码

         public void Flush(); 将工作流的当前状态保存到 text 属性。

           public void Load(); 从text 属性中包含的 Xaml中加载工作流。

           那么在此类中我们需要熟悉几个基本属性以及方法调用。

                2.DesignerMetadata类,Contains metadata for the designer.就英文字面来看就理解为设计器元数据。

            在此类中我们需要熟悉:

          public void Register(); msdn的解释是Registers the runtime metadata.

                3.ToolboxControl 类,工具箱,此时想想VS左边熟悉的工具箱就明白了,哈哈。

          因为WF中会有各种类型的Activitys,我们需要将这些Activitys注册到工具箱上,以便能直接拖放到WorkflowDesigner 当前实例中。

         4.UIElement类,System.Windows.UIElement 是 WPF 核心级实现的基类,该类建立在 Windows Presentation Foundation(WPF)

                    元素和基本表示特征基础上。因为本例子是在windows form上面实现的,所以会用到此类。

        至此,我们了解了4个类,大至可以这样理解,一个设计面板,一个工具箱,一个元数据注册,一个呈现面板,工具箱的容器。

      二:上面我们熟悉了基本知识,现在我们进入码农最喜欢的环节,编码。

         1.代码实现。

            1)构建用户控件,界面设计,采用panel和splitter布局,这两个控件布局技巧是,先panel,后splitter,先左后右,先上后下,记住此口诀。

            电脑上没有安装好的图片编辑软件,呵呵。设计初图是:

            

         左边放工具箱,中间放设计器,右边放属性框,传统的windows界面布局。

         2.用户控件代码实现,采用wpf中elementHost控件作为容器,呈现工具箱设计器属性框等。

          核心类factory.cs

          

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Activities.Presentation;
    using System.Activities.Presentation.Hosting;
    using System.Windows;
    using System.Windows.Controls;
    using System.Activities.Presentation.Toolbox;
    using System.Activities.Statements;

    namespace WindowsFormsApp
    {
    public class factory
    {
    private WorkflowDesigner wd;

    private string DefaultXamlActivity
    {
    get
    {
    return @"<Activity x:Class='EmptyActivity' mva:VisualBasic.Settings='Assembly references and imported namespaces serialized as XML namespaces' xmlns='http://schemas.microsoft.com/netfx/2009/xaml/activities' xmlns:mva='clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' />";
    }
    }

    public void RegisterMetadata()
    {
    System.Activities.Core.Presentation.DesignerMetadata designers = new System.Activities.Core.Presentation.DesignerMetadata();
    designers.Register();
    }

    public UIElement LoadDesigner(string xaml)
    {
    this.wd = new WorkflowDesigner();
    this.wd.Context.Items.GetValue<ReadOnlyState>().IsReadOnly = false;

    this.wd.ModelChanged += delegate(object source, EventArgs args)
    {
    this.wd.Flush();
    };

    this.wd.Text = string.IsNullOrEmpty(xaml) ? this.DefaultXamlActivity : xaml;
    this.wd.Load();

    Grid.SetColumn(this.wd.View, 1);
    UIElement element = this.wd.View;
    element.IsEnabled = true;
    element.IsHitTestVisible = true;
    return element;

    }

    public UIElement LoadPropertyInspector()
    {
    Grid.SetColumn(wd.PropertyInspectorView, 2);
    return wd.PropertyInspectorView;
    }

    public UIElement LoadToolBox()
    {
    ToolboxControl tc = GetToolboxControl();
    Grid.SetColumn(tc, 0);
    return tc;
    }

    private ToolboxControl GetToolboxControl()
    {
    ToolboxControl ctrl = new ToolboxControl();

    #region MS Built-in Activity
    ToolboxCategory categoryFlowchart = new ToolboxCategory("Flowchart")
    {
    new ToolboxItemWrapper(typeof(Flowchart)),
    new ToolboxItemWrapper(typeof(FlowDecision))
    };

    ToolboxCategory categoryCollection = new ToolboxCategory("Collection")
    {
    new ToolboxItemWrapper(typeof(AddToCollection<>)),
    new ToolboxItemWrapper(typeof(ClearCollection<>)),
    new ToolboxItemWrapper(typeof(ExistsInCollection<>)),
    new ToolboxItemWrapper(typeof(RemoveFromCollection<>)),
    };

    ToolboxCategory categoryPrimitives = new ToolboxCategory("Primitives")
    {
    new ToolboxItemWrapper(typeof(Assign)),
    new ToolboxItemWrapper(typeof(Assign<>)),
    new ToolboxItemWrapper(typeof(Delay)),
    new ToolboxItemWrapper(typeof(InvokeMethod)),
    new ToolboxItemWrapper(typeof(WriteLine)),
    };

    ToolboxCategory categoryControlFlow = new ToolboxCategory("ControlFlow")
    {
    new ToolboxItemWrapper(typeof(DoWhile)),
    new ToolboxItemWrapper(typeof(ForEach<>)),
    new ToolboxItemWrapper(typeof(If)),
    new ToolboxItemWrapper(typeof(Parallel)),
    new ToolboxItemWrapper(typeof(ParallelForEach<>)),
    new ToolboxItemWrapper(typeof(Pick)),
    new ToolboxItemWrapper(typeof(PickBranch)),
    new ToolboxItemWrapper(typeof(Sequence)),
    new ToolboxItemWrapper(typeof(Switch<>)),
    new ToolboxItemWrapper(typeof(While)),
    };

    ToolboxCategory categoryTransaction = new ToolboxCategory("Transaction")
    {
    new ToolboxItemWrapper(typeof(CancellationScope)),
    new ToolboxItemWrapper(typeof(CompensableActivity)),
    new ToolboxItemWrapper(typeof(Compensate)),
    new ToolboxItemWrapper(typeof(Confirm)),
    new ToolboxItemWrapper(typeof(TransactionScope)),
    };

    ToolboxCategory categoryErrorHandling = new ToolboxCategory("Error Handling")
    {
    new ToolboxItemWrapper(typeof(Rethrow)),
    new ToolboxItemWrapper(typeof(Throw)),
    new ToolboxItemWrapper(typeof(TryCatch)),
    };
    #endregion

    ctrl.Categories.Add(categoryPrimitives);
    ctrl.Categories.Add(categoryControlFlow);
    ctrl.Categories.Add(categoryErrorHandling);
    ctrl.Categories.Add(categoryFlowchart);
    ctrl.Categories.Add(categoryTransaction);
    ctrl.Categories.Add(categoryCollection);

    return ctrl;
    }
    }
    }


          在用户控件中只要实现factory这个类即可:

         

    View Code
    private factory factory = new factory();

    public wf()
    {
    InitializeComponent();
    factory.RegisterMetadata();
    elementHost1.Child = factory.LoadToolBox();
    elementHost2.Child = factory.LoadDesigner("");
    elementHost3.Child = factory.LoadPropertyInspector();
    }

        

      三:到此,整个代码已经写完,上一张运行效果图.

        

      

      四:朋友们,是不是很简单啊,呵呵。要不也动手试试看。

        另外:在哪里上传代码?怎么没有找到了?

      

         

  • 相关阅读:
    轻轻松松看懂Spring AOP源码
    centos7安装openjdk8
    使用fiddler做弱网测试
    测试术语-好东西要跟大家一块分享-2
    测试思想-好东西与大家分享-1
    session、token、cookie的区别
    接口测试和功能测试的区别
    常见bug解析-移动端
    接口测试的简介
    软件测试基本理论
  • 原文地址:https://www.cnblogs.com/wucj/p/2429499.html
Copyright © 2011-2022 走看看