WWF3追踪功能<WWF第六篇>
WWF工作流提供了Tracking跟踪功能来对工作流实例及其所包含的活动在运行时的状态进行跟踪,以便用户在需要时可以通过这些历史信息进行分析。WWF的Tracking跟踪功能是通过"SqlTrackingService"服务自动完成的,它与WWF的Persistence持续化功能一样,会将所需的状态信息自动保存到SQLServer数据库中。WWF的持续化功能只是保存工作流实例从开始运行到最终结束这个生命周期内的信息,工作流结束后相关数据即被清空。WWF的Tracking跟踪功能为用户提供了工作流实例运行时的历史信息,这样用户就可以在需要时对它进行查询。
与Persistence持续化功能一样,在使用WWF的Tracking功能前必须在SQL Server数据库中创建相应的数据表。打开路径"C:\Windows\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\zh-CHS(或EN)",该路径下有两个SQL文件:"Tracking_Logic.sql"和"Tracking_Schema.sql"。用户打开SQL Server先创建一个新的数据库"Tracking"。并在它的基础上运行这两个SQL脚本,创建后的数据库结构和存储过程如下:
一、WorkflowTrackingRecord
工作流在运行时有很多种状态。不同的事件代表不同的状态,这些状态可以由WWF的Tracking功能自动保存到SQLServer数据库中,用户可以通过"sqlTrackingWorkflowInstance"对象中的"WorkflowEvents"子对象对其信息进行查看。
状态名称 | 事件名称 | 状态描述 |
Completed | WorkflowCompleted | 当工作流结束时的状态 |
Terminated | WorkflowTerminated | 当工作流终止时的状态 |
Suspended | WorkflowSuspended | 当工作流暂停时的状态 |
Aborted | WorkflowAborted | 当工作流失败时的状态 |
Created | WorkflowCreated | 当工作流创建时的状态 |
Idle | WorkflowIdled | 当工作流空闲时的状态 |
Loaded | WorkflowLoaded | 当工作流被加载时的状态 |
Persisted | WorkflowPersisted | 当工作流被持续化时的状态 |
Resumed | WorkflowResumed | 当工作流重新启动时的状态 |
Started | WorkflowStarted | 当工作流开始启动时的状态 |
Unloaded | WorkflowUnloaded | 当工作流被卸载时的状态 |
Exception | 无 | 当工作流发生异常时的状态 |
示例:
创建一个顺序类型的工作流项目,添加一个Delay活动来观察工作流的"Idle"状态,然后拖入一个IfElse活动,并在它左边的分支中添加一个Suspend暂停活动,在它的右边的分支中添加一个Terminate终止活动,以分别来观察工作流的"Suspended"和"Terminated"状态,最后在IfElse活动后添加一个Code活动,来提供用户工作流被重新启动并即将结束。
代码如下:
//在工作流定义一个属性"Condition",用作ifElse活动的逻辑判断条件。
private bool condition;
public bool Condition
{
get { return condition; }
set { condition = value; }
} public Workflow1()
{
InitializeComponent();
} private void Code1(object sender, EventArgs e)
{
MessageBox.Show("工作流被重新启动!");
} private void ifElseCondition(object sender, ConditionalEventArgs e)
{
e.Result = Condition;
}
创建一个Windows应用程序,界面如下。根据用户选择的判断条件工作流将执行ifElse分支。当用户点击TrackingWFEvent按钮后,界面就会显示工作流状态的变迁过程信息。
代码如下:
public partial class Form1 : Form
{
static AutoResetEvent waitHandle = new AutoResetEvent(false);
const string connectionString = "Initial Catalog=Tracking;Data Source=CZZ;Integrated Security=SSPI;"; private WorkflowRuntime workflowRuntime = null; public Form1()
{
InitializeComponent(); workflowRuntime = new WorkflowRuntime(); workflowRuntime.AddService(new SqlTrackingService(connectionString)); workflowRuntime.WorkflowCompleted += OnWorkflowCompleted;
workflowRuntime.WorkflowTerminated += OnWorkflowTerminated;
workflowRuntime.WorkflowSuspended += OnWorkflowSuspend; workflowRuntime.StartRuntime();
} //如果工作流暂停了,那么就将其重新启动
//触发工作流的"WorkflowSuspended"事件,并将工作流的状态设置为"Suspended"。
static void OnWorkflowSuspend(object sender, WorkflowSuspendedEventArgs instance)
{
instance.WorkflowInstance.Resume();
waitHandle.Set();
}
//当工作流结束时,将各种工作流的事件添加到列表中
//当工作流正常运行结束时吗,也需要将它运行的状态信息显示到界面列表中。通过delegate代理实现
public void OnWorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
{
AddListViewItem addListItem = new AddListViewItem(AddListViewItemAsync);
Invoke(addListItem, e.WorkflowInstance.InstanceId); waitHandle.Set();
}
//当工作流终止时,将各种工作流的事件添加到列表中
//当Terminate活动执行时将触发工作流的"WorkflowTerminated"事件,并将工作流运行状态设置为"Terminated"。
//由于工作流终止了,因此它的后续活动Code将不再触发。但由于工作流与应用程序不在同一个线程中,因此需要通过deletegate代理来实现。
public void OnWorkflowTerminated(object sender, WorkflowTerminatedEventArgs e)
{
AddListViewItem addListItem = new AddListViewItem(AddListViewItemAsync);
Invoke(addListItem, e.WorkflowInstance.InstanceId);
waitHandle.Set();
} //通过delegate代理将各种工作流的事件添加到列表中
private delegate void AddListViewItem(Guid instanceId);
public void AddListViewItemAsync(Guid instanceId)
{
//工作流在运行时通过"SqlTrackingService"服务已经将工作流的状态信息自动保存到数据库中,可以通过
//"SqlTrackingQuery"类来对SQL Server中"Tracking"数据库进行查询
SqlTrackingQuery sqlTrackingQuery = new SqlTrackingQuery(connectionString);
SqlTrackingWorkflowInstance sqlTrackingWorkflowInstance;
sqlTrackingQuery.TryGetWorkflow(instanceId, out sqlTrackingWorkflowInstance); if (sqlTrackingWorkflowInstance != null)
{
foreach (WorkflowTrackingRecord workflowTrackingRecord in sqlTrackingWorkflowInstance.WorkflowEvents)
{
this.ListView1.Items.Add(new ListViewItem(new String[] { workflowTrackingRecord.TrackingWorkflowEvent.ToString(), workflowTrackingRecord.EventDateTime.ToString() }));
}
}
} //当用户点击按钮时,应用程序会将下拉列表中的信息作为参数传递给工作流,工作流中的ifElse活动根据其信息执行不同逻辑分支,并将列表内容清空。
private void button1_Click(object sender, EventArgs e)
{
Dictionary<string, object> parameters = new Dictionary<string, object>(); parameters.Add("Condition", Convert.ToBoolean(this.comboBox1.Text.ToString())); WorkflowInstance workflowInstance = workflowRuntime.CreateWorkflow(typeof(WorkflowConsoleApplication1.Workflow1), parameters);
workflowInstance.Start(); this.ListView1.Items.Clear();
}
}
运行结果如下:
留意到,只有当选择true时,codeActivity1才会执行,因为如果在前面中已经Terminate,工作流就被终止了。
上面的ListView就是工作流整个状态的变迁过程。
另外,如果刚才运行正常的程序增加了新的活动后,工作流会报错。这是因为工作流在运行时会通过"SqlTrackingService"服务将工作流及其工作流上的所有活动偶读注册到SQLServer数据库中。当再次运行时检测到数据库中该工作流已经存在,那么将不再进行注册,因此对新增加的活动进行跟踪时就会出现错误。可以通过重命名工作流或再次注册工作流就可以解决了。
二、ActivityTrackingRecord
工作流是一组活动所构成,用户往往也需要了解各活动的执行情况,这可以通过"sqlTrackingWorkflowInstance"对象中的"ActivityEvents"子对象来获取相关历史信息。
状态名称 | 状态描述 |
Canceling | 当活动被取消时触发该状态 |
Closed | 当活动关闭时触发该状态 |
Compensating | 当活动执行补偿时触发该状态 |
Executing | 当活动执行时触发该状态 |
Faulting | 当活动失败时触发该状态 |
Initialized | 当活动被初始化时触发该状态 |
其状态转换关系如下:
创建一个顺序类型的工作流项目,然后在工作流的设计界面中添加一个Code活动,其工作流界面如下:
代码如下:
public sealed partial class Workflow1 : SequentialWorkflowActivity
{
public Workflow1()
{
InitializeComponent();
} private void Code1Execute(object sender, EventArgs e)
{
int i = ;
int j = ;
int k = i / j;
} private void Code2Execute(object sender, EventArgs e)
{
MessageBox.Show("捕捉到除数为0的异常!");
}
}
创建一个WinForm程序,界面如下:
代码如下:
public partial class Form1 : Form
{
static AutoResetEvent waitHandle = new AutoResetEvent(false);
const string connectionString = "Initial Catalog=Tracking;Data Source=CZZ;Integrated Security=SSPI;"; private WorkflowRuntime workflowRuntime = null; public Form1()
{
InitializeComponent(); workflowRuntime = new WorkflowRuntime(); workflowRuntime.AddService(new SqlTrackingService(connectionString)); workflowRuntime.WorkflowCompleted += OnWorkflowCompleted;
workflowRuntime.WorkflowTerminated += OnWorkflowTerminated;
workflowRuntime.WorkflowSuspended += OnWorkflowSuspend; workflowRuntime.StartRuntime();
} //如果工作流暂停了,那么就将其重新启动
//触发工作流的"WorkflowSuspended"事件,并将工作流的状态设置为"Suspended"。
static void OnWorkflowSuspend(object sender, WorkflowSuspendedEventArgs instance)
{
instance.WorkflowInstance.Resume();
waitHandle.Set();
}
//当工作流结束时,将各种工作流的事件添加到列表中
//当工作流正常运行结束时吗,也需要将它运行的状态信息显示到界面列表中。通过delegate代理实现
public void OnWorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
{
AddListViewItem addListItem = new AddListViewItem(AddListViewItemAsync);
Invoke(addListItem, e.WorkflowInstance.InstanceId); waitHandle.Set();
}
//当工作流终止时,将各种工作流的事件添加到列表中
//当Terminate活动执行时将触发工作流的"WorkflowTerminated"事件,并将工作流运行状态设置为"Terminated"。
//由于工作流终止了,因此它的后续活动Code将不再触发。但由于工作流与应用程序不在同一个线程中,因此需要通过deletegate代理来实现。
public void OnWorkflowTerminated(object sender, WorkflowTerminatedEventArgs e)
{
AddListViewItem addListItem = new AddListViewItem(AddListViewItemAsync);
Invoke(addListItem, e.WorkflowInstance.InstanceId);
waitHandle.Set();
} //通过delegate代理将各种工作流的事件添加到列表中
private delegate void AddListViewItem(Guid instanceId);
public void AddListViewItemAsync(Guid instanceId)
{
//对活动运行状态跟踪的方法与工作流运行状态进行跟踪的方法类似,只是在获取活动状态使用的是"sqlTrackingWorkflowInstance"对象中的"ActivityEvents"子对象。
//因此只需要对"AddListViewItemAsync"方法进行修改
SqlTrackingQuery sqlTrackingQuery = new SqlTrackingQuery(connectionString);
SqlTrackingWorkflowInstance sqlTrackingWorkflowInstance;
sqlTrackingQuery.TryGetWorkflow(instanceId, out sqlTrackingWorkflowInstance); if (sqlTrackingWorkflowInstance != null)
{
foreach (ActivityTrackingRecord activityTrackingRecord in sqlTrackingWorkflowInstance.ActivityEvents)
{
this.ListView1.Items.Add(new ListViewItem(new String[] { activityTrackingRecord.ExecutionStatus.ToString(), activityTrackingRecord.EventDateTime.ToString(), activityTrackingRecord.QualifiedName.ToString() }));
}
}
} //当用户点击按钮时,应用程序会将下拉列表中的信息作为参数传递给工作流,工作流中的ifElse活动根据其信息执行不同逻辑分支,并将列表内容清空。
private void button1_Click(object sender, EventArgs e)
{
WorkflowInstance workflowInstance = workflowRuntime.CreateWorkflow(typeof(WorkflowConsoleApplication1.Workflow1));
workflowInstance.Start();
this.ListView1.Items.Clear();
}
}
显示效果:
三、UserTrackingRecord
用户可以通过"TrackingData"来为每个活动添加自定义的状态或信息。并且可以通过"sqlTrackingWorkflowInstance"对象中的"UserEvents"子对象将这些信息从数据库中获取出来。
创建一个工作流如下,只有两个Code活动:
代码如下:
public sealed partial class Workflow2 : SequentialWorkflowActivity
{
public Workflow2()
{
InitializeComponent();
} private void Code1(object sender, EventArgs e)
{
TrackData("key1","Code1执行!");
} private void Code2(object sender, EventArgs e)
{
TrackData("key2", "Code2执行!");
}
}
新建一个WinForm应用程序,对用户自定义信息的跟踪方法与对工作流运行状态的跟踪方法基本相同,只是在获取用户自定义信息时使用的是"sqlTrackingWorkflowInstance对象中的UserEvents"子对象。
界面如下:
与上面第二个示例相比,唯一改变的是委托代码如下:
//通过delegate代理将各种工作流的事件添加到列表中
private delegate void AddListViewItem(Guid instanceId);
public void AddListViewItemAsync(Guid instanceId)
{
//对活动运行状态跟踪的方法与工作流运行状态进行跟踪的方法类似,只是在获取活动状态使用的是"sqlTrackingWorkflowInstance"对象中的"UserEvents"子对象。
//因此只需要对"AddListViewItemAsync"方法进行修改
SqlTrackingQuery sqlTrackingQuery = new SqlTrackingQuery(connectionString);
SqlTrackingWorkflowInstance sqlTrackingWorkflowInstance;
sqlTrackingQuery.TryGetWorkflow(instanceId, out sqlTrackingWorkflowInstance); if (sqlTrackingWorkflowInstance != null)
{
foreach (UserTrackingRecord userTrackingRecord in sqlTrackingWorkflowInstance.UserEvents)
{
this.ListView1.Items.Add(new ListViewItem(new String[] { userTrackingRecord.UserDataKey, userTrackingRecord.UserData.ToString(), userTrackingRecord.EventDateTime.ToString(), userTrackingRecord.QualifiedName.ToString() }));
}
}
}
显示效果如下:
四、TrackingRuleActionEvent
用于跟踪逻辑判断的。例如Policy活动。该活动可以根据用户定义的规则"Rule"来进行判断,并根据其结果来分别执行"Then Actions"和"Else Actions"中的操作。WWF的Tracking功能同样可以对基于逻辑判断活动所执行的判断结果进行跟踪。
对于基于逻辑判断类型活动的判断结果,进行跟踪的方法与用户自定义信息的跟踪方法基本相同。只需要将UserEvents子对象类型转换为"RuleActionTrackingEvent"类型即可。
foreach (UserTrackingRecord userTrackingRecord in sqlTrackingWorkflowInstance.UserEvents)
{
RuleActionTrackingEvent rule = (RuleActionTrackingEvent)userTrackingRecord.UserData;
this.ListView1.Items.Add(new ListViewItem(new String[] { userTrackingRecord.QualifiedName, rule.RuleName, rule.ConditionResult.ToString() }));
}
五、TraclingProfile
WWF的"TrackingProfile"文件对"Tracking"功能提供的信息进行过滤,并可以根据用户的不通需要定义不同版本的"TrackingProfile"文件。
在构建"TrackingProfile"文件时,将使用到"TrackingService"和"TrackingChannel"两个抽象类。需要自定义两个类来继承并实现两个抽象类中的内容。应用程序与"TrackingService"和"TrackingChannel"的关系如下:
新建一个工作流如下:
Sequence容器的"Fault Handlers"视图中,添加一个FaultHandler活动来捕捉"除数为0"的异常,并在其内部添加一个Code活动来对该异常处理。
代码如下:
public sealed partial class TrackingProfile: SequentialWorkflowActivity
{
public TrackingProfile()
{
InitializeComponent();
} private void Code1Exe(object sender, EventArgs e)
{
int i = ;
int j = ;
int k = ;
k = i / j;
} private void Code2Exe(object sender, EventArgs e)
{
TrackData("key1", "发生除数为0的异常错误");
} private void Code3Exe(object sender, EventArgs e)
{
TrackData("key2", "工作流重新启动");
}
}
MyTrackingChannel:
public class MyTrackingChannel : TrackingChannel
{
private TrackingParameters parameters = null;
private Form1 trackingForm = new Form1(); public MyTrackingChannel(TrackingParameters parameters, Form1 form)
{
this.parameters = parameters; trackingForm = form;
} protected override void InstanceCompletedOrTerminated()
{ } protected override void Send(TrackingRecord record)
{
if (record is WorkflowTrackingRecord)
{
TrackingWFRecord((WorkflowTrackingRecord)record);
}
if (record is ActivityTrackingRecord)
{
TrackingActivityRecord((ActivityTrackingRecord)record);
}
if (record is UserTrackingRecord)
{
TrackingUserRecord((UserTrackingRecord)record);
}
} //对工作流对象的跟踪
public void TrackingWFRecord(WorkflowTrackingRecord record)
{
Form1.AddListViewWF addListItem = new Form1.AddListViewWF(trackingForm.AddListViewMethodWF); TrackingInfo proInfo = new TrackingInfo();
proInfo.Date = record.EventDateTime.ToString();
proInfo.EventName = record.TrackingWorkflowEvent.ToString(); trackingForm.Invoke(addListItem, proInfo); }
//对活动的跟踪
public void TrackingActivityRecord(ActivityTrackingRecord record)
{
Form1.AddListViewActivity addListItem = new Form1.AddListViewActivity(trackingForm.AddListViewMethodActivity); TrackingInfo proInfo = new TrackingInfo();
proInfo.Date = record.EventDateTime.ToString();
proInfo.EventName = record.ExecutionStatus.ToString();
proInfo.ActivityName = record.QualifiedName.ToString(); trackingForm.Invoke(addListItem, proInfo);
}
//对用户自定义状态信息的跟踪
public void TrackingUserRecord(UserTrackingRecord record)
{
Form1.AddListViewUser addListItem = new Form1.AddListViewUser(trackingForm.AddListViewMethodUser); TrackingInfo proInfo = new TrackingInfo();
proInfo.Date = record.EventDateTime.ToString();
proInfo.Key = record.UserDataKey;
proInfo.ActivityName = record.QualifiedName.ToString();
proInfo.EventName = record.UserData.ToString();
trackingForm.Invoke(addListItem, proInfo);
}
}
MyTrackingService:
public class MyTrackingService : TrackingService
{
private Form1 tform; public MyTrackingService(Form1 form)
{
tform = form;
} protected override System.Workflow.Runtime.Tracking.TrackingProfile GetProfile(Guid workflowInstanceId)
{
throw new Exception("The method or operation is not implemented.");
} protected override System.Workflow.Runtime.Tracking.TrackingProfile GetProfile(Type workflowType, Version profileVersionId)
{
throw new Exception("The method or operation is not implemented.");
} protected override TrackingChannel GetTrackingChannel(TrackingParameters parameters)
{
return new MyTrackingChannel(parameters, tform);
} protected override bool TryGetProfile(Type workflowType, out System.Workflow.Runtime.Tracking.TrackingProfile profile)
{
//如果是4.0.0就哪有追踪用户状态的TrackingProfile
if (tform.PVersion == "4.0.0")
{
profile = GetProfile();
}
else
{
profile = GetProfile401();
}
return true;
} protected override bool TryReloadProfile(Type workflowType, Guid workflowInstanceId, out System.Workflow.Runtime.Tracking.TrackingProfile profile)
{
profile = null;
return false;
} private static TrackingProfile GetProfile()
{
//创建一个Tracking Profile文件
TrackingProfile profile = new TrackingProfile();
profile.Version = new Version("4.0.0"); //添加对活动进行跟踪的节点
ActivityTrackPoint activityTrackPoint = new ActivityTrackPoint();
ActivityTrackingLocation activityLocation = new ActivityTrackingLocation(typeof(Activity));
activityLocation.MatchDerivedTypes = true; IEnumerable<ActivityExecutionStatus> statuses = Enum.GetValues(typeof(ActivityExecutionStatus)) as IEnumerable<ActivityExecutionStatus>;
foreach (ActivityExecutionStatus status in statuses)
{
activityLocation.ExecutionStatusEvents.Add(status);
} activityTrackPoint.MatchingLocations.Add(activityLocation);
profile.ActivityTrackPoints.Add(activityTrackPoint); //添加对工作流进行跟踪的节点
WorkflowTrackPoint workflowTrackPoint = new WorkflowTrackPoint();
workflowTrackPoint.MatchingLocation = new WorkflowTrackingLocation(); foreach (TrackingWorkflowEvent workflowEvent in Enum.GetValues(typeof(TrackingWorkflowEvent)))
{
workflowTrackPoint.MatchingLocation.Events.Add(workflowEvent);
}
profile.WorkflowTrackPoints.Add(workflowTrackPoint); //添加对用户自定义信息进行跟踪的节点(4.0.0版本有用户自定义状态追踪)
UserTrackPoint userTrackPoint = new UserTrackPoint();
UserTrackingLocation userLocation = new UserTrackingLocation(); userLocation.ActivityType = typeof(Activity);
userLocation.MatchDerivedActivityTypes = true; userLocation.ArgumentType = typeof(object);
userLocation.MatchDerivedArgumentTypes = true; userTrackPoint.MatchingLocations.Add(userLocation);
profile.UserTrackPoints.Add(userTrackPoint);
return profile;
} private static TrackingProfile GetProfile401()
{
//创建一个Tracking Profile文件
TrackingProfile profile = new TrackingProfile();
profile.Version = new Version("4.0.1"); //添加对活动进行跟踪的节点
ActivityTrackPoint activityTrackPoint = new ActivityTrackPoint();
ActivityTrackingLocation activityLocation = new ActivityTrackingLocation(typeof(Activity));
activityLocation.MatchDerivedTypes = true; IEnumerable<ActivityExecutionStatus> statuses = Enum.GetValues(typeof(ActivityExecutionStatus)) as IEnumerable<ActivityExecutionStatus>;
foreach (ActivityExecutionStatus status in statuses)
{
activityLocation.ExecutionStatusEvents.Add(status);
}
activityLocation.ExecutionStatusEvents.Remove(ActivityExecutionStatus.Faulting); activityTrackPoint.MatchingLocations.Add(activityLocation);
profile.ActivityTrackPoints.Add(activityTrackPoint); //添加对工作流进行跟踪的节点
WorkflowTrackPoint workflowTrackPoint = new WorkflowTrackPoint();
workflowTrackPoint.MatchingLocation = new WorkflowTrackingLocation(); foreach (TrackingWorkflowEvent workflowEvent in Enum.GetValues(typeof(TrackingWorkflowEvent)))
{
workflowTrackPoint.MatchingLocation.Events.Add(workflowEvent);
}
workflowTrackPoint.MatchingLocation.Events.Remove(TrackingWorkflowEvent.Exception);
profile.WorkflowTrackPoints.Add(workflowTrackPoint);
//4.0.1版本在这个地方少了对用户自定义状态的跟踪
return profile;
}
}
TrackingInfo:
public class TrackingInfo
{
private string name;
private string date;
private string activityname;
private string key; public string EventName
{
get { return name; }
set { name = value; }
} public string Date
{
get { return date; }
set { date = value; }
} public string ActivityName
{
get { return activityname; }
set { activityname = value; }
} public string Key
{
get { return key; }
set { key = value; }
}
}
代码架构如下:
Winform界面如下:
Winform代码如下:
public partial class Form1 : Form
{
private string pversion;
public string PVersion
{
set { pversion = value; }
get { return pversion; }
} static AutoResetEvent waitHandle = new AutoResetEvent(false);
const string connectionString = "Initial Catalog=Tracking;Data Source=CZZ;Integrated Security=SSPI;"; private WorkflowRuntime workflowRuntime=null; public Form1()
{
InitializeComponent(); workflowRuntime = new WorkflowRuntime(); workflowRuntime.WorkflowSuspended += OnWorkflowSuspend; workflowRuntime.AddService(new MyTrackingService(this)); workflowRuntime.AddService(new SqlTrackingService(connectionString)); workflowRuntime.StartRuntime();
} //如果工作流暂停了,那么就将其重新启动
static void OnWorkflowSuspend(object sender, WorkflowSuspendedEventArgs instance)
{
instance.WorkflowInstance.Resume();
waitHandle.Set();
} //启动工作流的实例,然后根据下拉列表中用户选择的内容传递给工作流。
private void button1_Click(object sender, EventArgs e)
{
this.ListViewActivity.Items.Clear();
this.ListViewUser.Items.Clear();
this.listViewWF.Items.Clear(); this.PVersion = this.comboBox1.Text.ToString(); WorkflowInstance workflowInstance = workflowRuntime.CreateWorkflow(typeof(WorkflowConsoleApplication1.Workflow2));
workflowInstance.Start();
} public delegate void AddListViewWF(TrackingInfo proInfo);
public void AddListViewMethodWF(TrackingInfo proInfo)
{
this.listViewWF.Items.Add(new ListViewItem(new String[] { proInfo.EventName, proInfo.Date }));
} public delegate void AddListViewActivity(TrackingInfo proInfo);
public void AddListViewMethodActivity(TrackingInfo proInfo)
{
this.ListViewActivity.Items.Add(new ListViewItem(new String[] { proInfo.EventName, proInfo.Date , proInfo.ActivityName}));
} public delegate void AddListViewUser(TrackingInfo proInfo);
public void AddListViewMethodUser(TrackingInfo proInfo)
{
this.ListViewUser.Items.Add(new ListViewItem(new String[] { proInfo.Key, proInfo.EventName, proInfo.Date, proInfo.ActivityName }));
}
}
显示效果如下:4.0.0显示用户自定义状态而4.0.1不显示。
WWF3追踪功能<WWF第六篇>的更多相关文章
- WWF3状态机工作流<WWF第七篇>
状态机是另外一种常见的工作流类型.它是以状态的变迁为驱动而进行业务流转的,是一定需要人为干预的,而不像顺序类型工作流那样可以按照事先设计好的业务流程一步一步依次执行下去. 一.状态机工作流范例 Sta ...
- 解剖SQLSERVER 第十六篇 OrcaMDF RawDatabase --MDF文件的瑞士军刀(译)
解剖SQLSERVER 第十六篇 OrcaMDF RawDatabase --MDF文件的瑞士军刀(译) http://improve.dk/orcamdf-rawdatabase-a-swiss-a ...
- 解剖SQLSERVER 第六篇 对OrcaMDF的系统测试里避免regressions(译)
解剖SQLSERVER 第六篇 对OrcaMDF的系统测试里避免regressions (译) http://improve.dk/avoiding-regressions-in-orcamdf-b ...
- Python之路【第十六篇】:Django【基础篇】
Python之路[第十六篇]:Django[基础篇] Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了O ...
- RabbitMQ学习总结 第六篇:Topic类型的exchange
目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...
- 第六篇 Replication:合并复制-发布
本篇文章是SQL Server Replication系列的第六篇,详细内容请参考原文. 合并复制,类似于事务复制,包括一个发布服务器,一个分发服务器和一个或多个订阅服务器.每一个发布服务器上可以定义 ...
- 第六篇 Integration Services:初级工作流管理
本篇文章是Integration Services系列的第六篇,详细内容请参考原文. 简介在前几篇文章中,我们关注使用增量加载方式加载数据.在本篇文章,我们将关注使用优先约束管理SSIS控制流中的工作 ...
- Python之路【第六篇】:socket
Python之路[第六篇]:socket Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字&quo ...
- [老老实实学WCF] 第六篇 元数据交换
老老实实学WCF 第六篇 元数据交换 通过前两篇的学习,我们了解了WCF通信的一些基本原理,我们知道,WCF服务端和客户端通过共享元数据(包括服务协定.服务器终结点信息)在两个 终结点上建立通道从而进 ...
随机推荐
- sqlite数据库执行full outer join
sqlite数据库执行full outer join时提示:RIGHT and FULL OUTER JOINs are not currently supported. sqlite数据库不支持(+ ...
- [CSS]如何正确使用ID和Class?
作者:DarkZone链接:https://www.zhihu.com/question/19550864/answer/23440690来源:知乎 以下摘自<精通CSS:高级Web标准解决方案 ...
- NeHe OpenGL教程 第二十八课:贝塞尔曲面
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- 何时要打开stm32的AFIO时钟
STM32的管脚配置一般有2个:Default和rinmap,如果使用default就不需要打开AFIO,否则使用后者就需要打开3个时钟:GPIO时钟.外设功能时钟和AFIO时钟. 一般在涉及外中断配 ...
- jquery判断checkbox是否选中及改变checkbox状态[转]
jquery判断checked的三种方法: .attr('checked): //看版本1.6+返回:”checked”或”undefined” ;1.5-返回:true或false .prop('c ...
- 关于Switch结构利用
三大流程结构,循环.分支.if ,循环与条件选择结构用的比较多,而swicth用的比较少,swicth可以用if代替,只不过麻烦,最终都能实现输入和输出的条件对应 Swicth利用 ...
- ios8消息快捷处理——暂无输入框
if (isiOS8) { //ios8的远程推送注册 NSSet *set = nil; #if 1 //1.创建消息上面要添加的动作(按钮的形式显示出来) UIMutableUserNotific ...
- IceGrid负载均衡部署 z
[IceGrid负载均衡部署步骤]1.环境主机1:IP=192.168.0.239,上面部署注册表服务器registry和节点node1,registry和node1运行在同一进程中:主机2:IP=1 ...
- Nginx+Keepalived主主负载均衡服务器
Nginx+keepalived主主负载均衡服务器测试实验环境: 主Nginx之一:192.168.11.27主Nginx之二:192.168.11.28Web服务器一:192.168.11.37We ...
- turing 项目引用
1.友盟自动更新 2.友盟统计 3.友盟消息推送 http://www.bejson.com/json2javapojo/ 引用bejson 解析JSON生成类,数组 private List< ...