WF 4 Rehosted Designer - 获取 foreach InArgument 值
WF 4 Rehosted Designer - get foreach InArgument Value
阅读本文后:
我定义了 ForEachFactory 如下:
public class ForEachFactory<T> : IActivityTemplateFactory
{
public Activity Create(DependencyObject target)
{
return new ForEach<T>
{
DisplayName = "ForEachFromFactory",
Body = new ActivityAction<T>
{
Argument = new DelegateInArgument<T>("item")
}
};
}
}
一切正常,但是否可以检查在我的案例中名为 "item" 的 DelegeateInArgument 如何更改其值?
所以如果我在变量部分定义了一个数组并用
{1, 2, 3} 我需要一种方法来检查 "item" 如何取值 1、2 然后是 3。
为了更准确,我添加了这张图片,在 foreach 内的 WriteLine activity 上有一个断点。当执行停止时,有没有办法找出 item 的值是什么?
编辑 1:
可能的解决方案 在我的例子中:
经过一番努力,我发现了一件有趣的事情:
在 ForEach 的正文中添加我的自定义活动之一,我能够像这样获得项目的值:
所以,我的 activity 来自:CodeActivity
在 protected override String[] Execute(CodeActivityContext context) 我正在做这个 job.To 老实说,这以某种方式解决了这个问题,但它只是可行的在我的自定义活动中。例如,如果我将 WriteLine 放在那里,我将无法检索该值。
您可以通过检查 ModelItem 树的父树并检查 DelegeateInArgument 来访问 ForEach activity 的 DelegeateInArgument。如果您需要一个特定的代码示例来实现这一点,我可能需要一些时间来编写示例代码。因为我已经很久没有这样做了,请参阅我在 msdn
上提出的问题
所以基本上你的断点在哪里,你可以访问变量值,因为这些值是用你的 activity 范围定义的 'variables'。然而 'item' 变量实际上只能从父循环 activity 访问。所以你必须得到当前正在执行的模型项 activity 然后向上遍历树找到包含所需 DelegateInArgument.
的父项
你能具体说说你想要达到的目标吗?是不是当您在重新托管的设计器中调试工作流时,您希望在 UI 中更改时向用户显示变量值?
编辑 - 添加跟踪示例
因此,如果您希望在工作流执行期间显示变量值,我们需要使用跟踪来实现这一点。在您使用作者的示例中,已经实现了一些基本的跟踪。因此,要实现您想要的扩展变量跟踪,您需要更改跟踪配置文件。
首先修改WorkflowDesignerHost.xaml.cs文件,修改RunWorkflow方法定义SimulatorTrackingParticipant如下。
SimulatorTrackingParticipant simTracker = new SimulatorTrackingParticipant()
{
TrackingProfile = new TrackingProfile()
{
Name = "CustomTrackingProfile",
Queries =
{
new CustomTrackingQuery()
{
Name = all,
ActivityName = all
},
new WorkflowInstanceQuery()
{
**States = {all },**
},
new ActivityStateQuery()
{
// Subscribe for track records from all activities for all states
ActivityName = all,
States = { all },
**Arguments = {all},**
// Extract workflow variables and arguments as a part of the activity tracking record
// VariableName = "*" allows for extraction of all variables in the scope
// of the activity
Variables =
{
{ all }
}
}
}
}
};
现在这将正确捕获所有工作流实例状态,而不仅仅是 Started/Completed。您还将捕获每个 activity 上记录跟踪数据而不仅仅是变量的所有参数。这很重要,因为 'variable' 感兴趣的实际上是(如前所述)DelegateInArgument。
因此,一旦我们更改了跟踪配置文件,我们还需要更改 SimulatorTrackingParticipant.cs 以提取我们现在正在跟踪的其他数据。
如果您更改 OnTrackingRecordReceived 方法以包含以下部分,这些部分将在执行期间捕获变量数据和参数数据。
protected void OnTrackingRecordReceived(TrackingRecord record, TimeSpan timeout)
{
System.Diagnostics.Debug.WriteLine(
String.Format("Tracking Record Received: {0} with timeout: {1} seconds.", record, timeout.TotalSeconds)
);
if (TrackingRecordReceived != null)
{
ActivityStateRecord activityStateRecord = record as ActivityStateRecord;
if (activityStateRecord != null)
{
IDictionary<string, object> variables = activityStateRecord.Variables;
StringBuilder vars = new StringBuilder();
if (variables.Count > 0)
{
vars.AppendLine("\n\tVariables:");
foreach (KeyValuePair<string, object> variable in variables)
{
vars.AppendLine(String.Format(
"\t\tName: {0} Value: {1}", variable.Key, variable.Value));
}
}
}
if (activityStateRecord != null)
{
IDictionary<string, object> arguments = activityStateRecord.Arguments;
StringBuilder args = new StringBuilder();
if (arguments.Count > 0)
{
args.AppendLine("\n\tArgument:");
foreach (KeyValuePair<string, object> argument in arguments)
{
args.AppendLine(String.Format(
"\t\tName: {0} Value: {1}", argument.Key, argument.Value));
}
}
//bubble up the args to the UI for the user to see!
}
if((activityStateRecord != null) && (!activityStateRecord.Activity.TypeName.Contains("System.Activities.Expressions")))
{
if (ActivityIdToWorkflowElementMap.ContainsKey(activityStateRecord.Activity.Id))
{
TrackingRecordReceived(this, new TrackingEventArgs(
record,
timeout,
ActivityIdToWorkflowElementMap[activityStateRecord.Activity.Id]
)
);
}
}
else
{
TrackingRecordReceived(this, new TrackingEventArgs(record, timeout,null));
}
}
}
希望对您有所帮助!
阅读本文后:
我定义了 ForEachFactory 如下:
public class ForEachFactory<T> : IActivityTemplateFactory
{
public Activity Create(DependencyObject target)
{
return new ForEach<T>
{
DisplayName = "ForEachFromFactory",
Body = new ActivityAction<T>
{
Argument = new DelegateInArgument<T>("item")
}
};
}
}
一切正常,但是否可以检查在我的案例中名为 "item" 的 DelegeateInArgument 如何更改其值? 所以如果我在变量部分定义了一个数组并用 {1, 2, 3} 我需要一种方法来检查 "item" 如何取值 1、2 然后是 3。
为了更准确,我添加了这张图片,在 foreach 内的 WriteLine activity 上有一个断点。当执行停止时,有没有办法找出 item 的值是什么?
编辑 1:
可能的解决方案 在我的例子中: 经过一番努力,我发现了一件有趣的事情:
在 ForEach 的正文中添加我的自定义活动之一,我能够像这样获得项目的值:
所以,我的 activity 来自:CodeActivity
在 protected override String[] Execute(CodeActivityContext context) 我正在做这个 job.To 老实说,这以某种方式解决了这个问题,但它只是可行的在我的自定义活动中。例如,如果我将 WriteLine 放在那里,我将无法检索该值。
您可以通过检查 ModelItem 树的父树并检查 DelegeateInArgument 来访问 ForEach activity 的 DelegeateInArgument。如果您需要一个特定的代码示例来实现这一点,我可能需要一些时间来编写示例代码。因为我已经很久没有这样做了,请参阅我在 msdn
上提出的问题所以基本上你的断点在哪里,你可以访问变量值,因为这些值是用你的 activity 范围定义的 'variables'。然而 'item' 变量实际上只能从父循环 activity 访问。所以你必须得到当前正在执行的模型项 activity 然后向上遍历树找到包含所需 DelegateInArgument.
的父项你能具体说说你想要达到的目标吗?是不是当您在重新托管的设计器中调试工作流时,您希望在 UI 中更改时向用户显示变量值?
编辑 - 添加跟踪示例
因此,如果您希望在工作流执行期间显示变量值,我们需要使用跟踪来实现这一点。在您使用作者的示例中,已经实现了一些基本的跟踪。因此,要实现您想要的扩展变量跟踪,您需要更改跟踪配置文件。
首先修改WorkflowDesignerHost.xaml.cs文件,修改RunWorkflow方法定义SimulatorTrackingParticipant如下。
SimulatorTrackingParticipant simTracker = new SimulatorTrackingParticipant()
{
TrackingProfile = new TrackingProfile()
{
Name = "CustomTrackingProfile",
Queries =
{
new CustomTrackingQuery()
{
Name = all,
ActivityName = all
},
new WorkflowInstanceQuery()
{
**States = {all },**
},
new ActivityStateQuery()
{
// Subscribe for track records from all activities for all states
ActivityName = all,
States = { all },
**Arguments = {all},**
// Extract workflow variables and arguments as a part of the activity tracking record
// VariableName = "*" allows for extraction of all variables in the scope
// of the activity
Variables =
{
{ all }
}
}
}
}
};
现在这将正确捕获所有工作流实例状态,而不仅仅是 Started/Completed。您还将捕获每个 activity 上记录跟踪数据而不仅仅是变量的所有参数。这很重要,因为 'variable' 感兴趣的实际上是(如前所述)DelegateInArgument。
因此,一旦我们更改了跟踪配置文件,我们还需要更改 SimulatorTrackingParticipant.cs 以提取我们现在正在跟踪的其他数据。
如果您更改 OnTrackingRecordReceived 方法以包含以下部分,这些部分将在执行期间捕获变量数据和参数数据。
protected void OnTrackingRecordReceived(TrackingRecord record, TimeSpan timeout)
{
System.Diagnostics.Debug.WriteLine(
String.Format("Tracking Record Received: {0} with timeout: {1} seconds.", record, timeout.TotalSeconds)
);
if (TrackingRecordReceived != null)
{
ActivityStateRecord activityStateRecord = record as ActivityStateRecord;
if (activityStateRecord != null)
{
IDictionary<string, object> variables = activityStateRecord.Variables;
StringBuilder vars = new StringBuilder();
if (variables.Count > 0)
{
vars.AppendLine("\n\tVariables:");
foreach (KeyValuePair<string, object> variable in variables)
{
vars.AppendLine(String.Format(
"\t\tName: {0} Value: {1}", variable.Key, variable.Value));
}
}
}
if (activityStateRecord != null)
{
IDictionary<string, object> arguments = activityStateRecord.Arguments;
StringBuilder args = new StringBuilder();
if (arguments.Count > 0)
{
args.AppendLine("\n\tArgument:");
foreach (KeyValuePair<string, object> argument in arguments)
{
args.AppendLine(String.Format(
"\t\tName: {0} Value: {1}", argument.Key, argument.Value));
}
}
//bubble up the args to the UI for the user to see!
}
if((activityStateRecord != null) && (!activityStateRecord.Activity.TypeName.Contains("System.Activities.Expressions")))
{
if (ActivityIdToWorkflowElementMap.ContainsKey(activityStateRecord.Activity.Id))
{
TrackingRecordReceived(this, new TrackingEventArgs(
record,
timeout,
ActivityIdToWorkflowElementMap[activityStateRecord.Activity.Id]
)
);
}
}
else
{
TrackingRecordReceived(this, new TrackingEventArgs(record, timeout,null));
}
}
}
希望对您有所帮助!