1. 程式人生 > >WF4.0以上使用代碼完整自定義動態生成執行工作流Xaml文件

WF4.0以上使用代碼完整自定義動態生成執行工作流Xaml文件

load 控制 brush 類型 rpv 返回 cap 並且 sco

給大家分享一下,如何完全使用代碼自定義的創建生成工作流文件(用代碼創建Xaml文件),並且動態加載運行所生成的工作流。

工作流生成後 在Xaml文件裏的主要節點如下:

輸入輸出參數

  <x:Members>
    <x:Property Name="Item" Type="InArgument(qm:RuleModel)" />
    <x:Property Name="Result" Type="OutArgument(x:Int32)" />
  </x:Members>

我們先創建工作流中使用的 輸入、輸出參數,主要是為了我們想自定數據或提供一些輔助方法到工作流中,

items:為自定義節點數據,主要是用來生成流程的數據(此數據為自己定義類的數據實體)

        public  ActivityBuilder CreateRule(string name,params RuleCondtionNode[] items)
        {
            var item = CreateProperty("Item",true); //生成輸入參數
            var Reulst = CreateProperty("Result",false);//生成輸出參婁
            ActivityBuilder wf = new
ActivityBuilder(); wf.Name = name; wf.Properties.Add(item);//把參數加入到創建的工作流中 wf.Properties.Add(Reulst); wf.Implementation = CreateNodes(items);//開始用自定義的數據 創建流程節點 return wf; }

創建輸入、輸出參數: RuleModel:為我自定義要傳入到工作流中使用的實體

        public  DynamicActivityProperty CreateProperty(string
name,bool inOut) { var item = new DynamicActivityProperty(); item.Name = name; item.Type = inOut? typeof(InArgument<RuleModel>): typeof(OutArgument<int>);//輸入 OR 輸出 是根據typeof 裏的類型來決定的 return item; }

創建流程節點:

   public Activity CreateNodes(params RuleCondtionNode[] model)
        {
            Sequence item = new Sequence();
            for (int i = 0; i < model.Length; i++)
            {
                item.Activities.Add(CreateNodeForType(model[i]));//把創建好的流程分去加入到活動中
            }
            return item;
        }

        public InArgument<bool> CreateIf(string codeStr)
        {
            return new CSharpValue<bool>(codeStr); //創建返回結果為 bool類型的表達式 這裏采用的是用C#代碼 主要為 IF 提示條件使用 
        }

        public Assign<T> CreateAssign<T>(string name,string codeStr)
        {
            var item = new Assign<T>(); //這裏創建的是 工作流中的 賦值操作 A=B
            item.To = new ArgumentReference<T>(name); // A
            item.Value = new CSharpValue<T>(codeStr); //B:這是創建的是 C#代碼表達式 Value是一個 InArgument<T> 類型 所以其它類型也行 我只是為了靈活采用C#代碼
            return item;
        }

通過上面幾步可實現一個簡單的工作流了,完整的代碼這裏並沒有,但是關鍵性的代碼都在。

下面到了生成 Xaml 字符串的環節:

 private static readonly string[] rfitem = new string[] { //這裏是我們需要在Xaml中生成的命名空間 很重要 我們想住工作流中添加任務擴展類靠它了
            "System",
            "System.Collections.Generic",
            "System.Linq",
            "System.Text",
            "QDRuleEngine.Model" //這是我自定義的類型
            };
        static RuleCreateHelper()
        {
            refList = rfitem.Select(c => new AssemblyReference() { AssemblyName = new System.Reflection.AssemblyName(c) }).ToList();//把命名空間的程序集加上
        }
        private static List<AssemblyReference> refList = new List<AssemblyReference>();//這裏是Xaml中生成的 引用程序集 沒有程序集大家懂的。生成好了也用不了


 public  string BuilderString(ActivityBuilder item)
        {
            TextExpression.SetNamespacesForImplementation(item, rfitem);//生成命名空間
            TextExpression.SetReferencesForImplementation(item, refList);//生成引用程序集
            StringBuilder sb = new StringBuilder();
            StringWriter tw = new StringWriter(sb);
            System.Xaml.XamlWriter xw = ActivityXamlServices.CreateBuilderWriter(new XamlXmlWriter(tw, new XamlSchemaContext()));//交給它來生成Xaml
            var xor = new XamlObjectReaderSettings();

            try
            {
                XamlObjectReader reader = new XamlObjectReader(item, xor);
                XamlServices.Transform(reader, xw);//通過此步我們就可以得到我們想要的 Xaml 字符串了
            }
            catch (Exception ex)
            {

            }

            return sb.ToString();//得到生成好的 Xaml 字符串  拿到這個字符串就可以 保存成Xaml工作流文件了
        }

命名空間引用:

  <TextExpression.NamespacesForImplementation>
    <sco:Collection x:TypeArguments="x:String">
      <x:String>System</x:String>
      <x:String>System.Collections.Generic</x:String>
      <x:String>System.Linq</x:String>
      <x:String>System.Text</x:String>
      <x:String>QDRuleEngine.Model</x:String>
    </sco:Collection>
  </TextExpression.NamespacesForImplementation>

引用程序集:

  <TextExpression.ReferencesForImplementation>
    <scg:List x:TypeArguments="AssemblyReference" Capacity="8">
      <AssemblyReference>System</AssemblyReference>
      <AssemblyReference>System.Collections.Generic</AssemblyReference>
      <AssemblyReference>System.Linq</AssemblyReference>
      <AssemblyReference>System.Text</AssemblyReference>
      <AssemblyReference>QDRuleEngine.Model</AssemblyReference>
    </scg:List>
  </TextExpression.ReferencesForImplementation>

我們生成好了想要的工作流後就是動態加載執行了:

       public  Activity LoadRule(string xmlStr)
        {
            Activity item = null;
            try
            {
                item = ActivityXamlServices.Load(new StringReader(xmlStr),//拿到我們生成好的Xaml字符串 轉換成工作流
                new ActivityXamlServicesSettings()
                {
                    CompileExpressions = true  //如果在生成時采用了C#代碼作為表達式時,必需把此值設為True 否則報錯
                });
            }
            catch (Exception ex)
            {
                item = null;
            }

            return item;
        }


WorkflowInvoker item = new WorkflowInvoker(rule);//

 RuleModel model = new RuleModel(info, null, null, null, condition, new List<RuleRunLogInfo>());
//這是我們自定義的實體 剛才為此實體加了 命名空間 和 程序集 此實體我們可在工作流中的C#表達式中使用 例:A.MyFunc(123) 表達式為字符串 註意雙引號
var result = item.Invoke(new Dictionary<string, object>()//傳入我們需要的參數 執行工作流 如果 傳入了工作流中沒有定義的參數 會報錯 { ["Item"] = model });
Console.Write(result["Result"]); //得到執行入返回的結果

有個完整的工作流生成示例代碼 有空再補上。

流程控制:

技術分享
  <Sequence>
    <If>
      <If.Condition>
        <InArgument x:TypeArguments="x:Boolean">
          <mca:CSharpValue x:TypeArguments="x:Boolean">Item.Condition.GetValue&lt;Int32&gt;("sql_2017010306288856")&gt;0</mca:CSharpValue>
        </InArgument>
      </If.Condition>
    </If>
  </Sequence>
流程控制

WF4.0以上使用代碼完整自定義動態生成執行工作流Xaml文件