最近在研究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

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這個類即可:

private factory factory = new factory();
public wf()
{
InitializeComponent();
factory.RegisterMetadata();
elementHost1.Child = factory.LoadToolBox();
elementHost2.Child = factory.LoadDesigner("");
elementHost3.Child = factory.LoadPropertyInspector();
}
三:到此,整個代碼已經寫完,上一張運行效果圖.
四:朋友們,是不是很簡單啊,呵呵。要不也動手試試看。
另外:在哪里上傳代碼?怎么沒有找到了?