工作流基础自定义 Assign Activity
Workflow foundation custom Assign Activity
我在我的设计器中定义了这个:
<sap:WorkflowItemPresenter>
<statements:Assign DisplayName="Assign"/>
</sap:WorkflowItemPresenter>
我认为如果我在那里添加 Assign 就可以简单地工作,但我错了。
[Browsable(false)]
public Activity Body { get; set; }
protected override void Execute(NativeActivityContext context)
{
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete));
}
/// <summary>
/// Called from Execute when Condition evaluates to true.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="instance">The instance.</param>
public void OnExecuteComplete(NativeActivityContext context, ActivityInstance instance)
{
//to be added
}
这是来自基础 class 的代码。
我根本不需要更改 Assign activity,我只想访问 NativeActivityContext。事实上,我正在尝试将其包装起来并在 OnExecuteComplete 方法中对上下文的属性进行一些检查。有没有办法做到这一点?
编辑 1:
DotNetHitMan 建议并向我展示了 如何使用这些跟踪,我确实成功地用他的解决方案解决了这个问题:
if (trackingEventArgs.Activity is Assign)
{
Assign ass = trackingEventArgs.Activity as Assign;
if (ass.To.Expression != null)
{
dynamic vbr = null;
if ((ass.To.Expression is VisualBasicReference<int>))
{
//vbr.ExpressionText will hold the value set in the To section of the Assign activity, one of the variables will reside here
vbr = ass.To.Expression as VisualBasicReference<int>;
}
else if ((ass.To.Expression is VisualBasicReference<string>))
{
vbr = ass.To.Expression as VisualBasicReference<string>;
}
ActivityStateRecord activityStateRecord = null;
if (trackingEventArgs.Record != null)
activityStateRecord = trackingEventArgs.Record as ActivityStateRecord;
if (activityStateRecord != null)
{
if (activityStateRecord.Arguments.Count > 0)
{
//checking if the variable defined in the To section is to be displayed in the watch window
GlobalFunctions.WatchWindowViewModel.VariableDefinition existingVariable = GlobalFunctions.WatchWindowViewModel.Instance.VariableExists(vbr.ExpressionText);
if (existingVariable != null)
{
foreach (KeyValuePair<string, object> argument in activityStateRecord.Arguments)
{
if (argument.Key.Equals("Value"))
{
Application.Current.Dispatcher.Invoke(
() =>
{
existingVariable.VariableValue.Clear();
existingVariable.VariableValue.Add(
argument.Value.ToString());
});
}
}
}
}
}
}
}
我的脸还是有点难看。在检查 Assign activity 的参数时,我得到了键 "Value"。但是,如果我定义了一个名为 "i" 的变量,并希望在执行此 Assign 时看到它的变化,我必须查看 VisualBasicReference<> 以检查在那里声明的变量的名称,就像上面的代码一样。这种方法确实有效,我设法涵盖了目前还不错的整数和字符串..但是我的代码中是否有任何快捷方式可以使用?
编辑 2
我今天有了一个新想法并付诸实践:
这里是库代码:
public sealed class CustomAssign : NativeActivity, IActivityTemplateFactory
{
[Browsable(false)]
public Activity Body { get; set; }
protected override void Execute(NativeActivityContext context)
{
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete));
}
/// <summary>
/// Called from Execute when Condition evaluates to true.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="instance">The instance.</param>
public void OnExecuteComplete(NativeActivityContext context, ActivityInstance instance)
{
//to be added
}
Activity IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
{
return new CustomAssign
{
Body = new Assign()
};
}
}
以及设计师:
<sap:ActivityDesigner x:Class="ARIASquibLibrary.Design.CustomAsignDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
xmlns:statements="http://schemas.microsoft.com/netfx/2009/xaml/activities" Collapsible="False" BorderThickness="20" BorderBrush="Transparent">
<sap:ActivityDesigner.Template>
<ControlTemplate TargetType="sap:ActivityDesigner">
<Grid>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</sap:ActivityDesigner.Template>
<DockPanel LastChildFill="True">
<sap:WorkflowItemPresenter Item="{Binding Path=ModelItem.Body, Mode=TwoWay}"/>
</DockPanel>
</sap:ActivityDesigner>
所以,简而言之:我在我的自定义 activity 中托管了 Assign activity 并更改了 ControlTemplate 以仅保留 ContentPresenter,而 ContentPresenter 又将成为 Assign .现在,通过将其拖到设计器中,您将拥有完全相同的原始外观,但可以编写代码并检查执行步骤:
protected override void Execute(NativeActivityContext context)
或
public void OnExecuteComplete(NativeActivityContext context, ActivityInstance instance)
这是为什么?通过context.DataContext可以得到这个activity所在作用域内的所有变量和参数,以便开发watchwindow.
无需处理每个变量类型,只需将表达式转换为其基接口即可。
ITextExpression vbr = ass.To.Expression as ITextExpression;
然后您可以只访问表达式文本 属性,而不用关心分配给表达式的变量类型。
GlobalFunctions.WatchWindowViewModel.VariableDefinition existingVariable = GlobalFunctions.WatchWindowViewModel.Instance.VariableExists(vbr.ExpressionText);
这应该适合(我希望)所有可以应用的变量类型。
我在我的设计器中定义了这个:
<sap:WorkflowItemPresenter>
<statements:Assign DisplayName="Assign"/>
</sap:WorkflowItemPresenter>
我认为如果我在那里添加 Assign 就可以简单地工作,但我错了。
[Browsable(false)]
public Activity Body { get; set; }
protected override void Execute(NativeActivityContext context)
{
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete));
}
/// <summary>
/// Called from Execute when Condition evaluates to true.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="instance">The instance.</param>
public void OnExecuteComplete(NativeActivityContext context, ActivityInstance instance)
{
//to be added
}
这是来自基础 class 的代码。
我根本不需要更改 Assign activity,我只想访问 NativeActivityContext。事实上,我正在尝试将其包装起来并在 OnExecuteComplete 方法中对上下文的属性进行一些检查。有没有办法做到这一点?
编辑 1:
DotNetHitMan 建议并向我展示了
if (trackingEventArgs.Activity is Assign)
{
Assign ass = trackingEventArgs.Activity as Assign;
if (ass.To.Expression != null)
{
dynamic vbr = null;
if ((ass.To.Expression is VisualBasicReference<int>))
{
//vbr.ExpressionText will hold the value set in the To section of the Assign activity, one of the variables will reside here
vbr = ass.To.Expression as VisualBasicReference<int>;
}
else if ((ass.To.Expression is VisualBasicReference<string>))
{
vbr = ass.To.Expression as VisualBasicReference<string>;
}
ActivityStateRecord activityStateRecord = null;
if (trackingEventArgs.Record != null)
activityStateRecord = trackingEventArgs.Record as ActivityStateRecord;
if (activityStateRecord != null)
{
if (activityStateRecord.Arguments.Count > 0)
{
//checking if the variable defined in the To section is to be displayed in the watch window
GlobalFunctions.WatchWindowViewModel.VariableDefinition existingVariable = GlobalFunctions.WatchWindowViewModel.Instance.VariableExists(vbr.ExpressionText);
if (existingVariable != null)
{
foreach (KeyValuePair<string, object> argument in activityStateRecord.Arguments)
{
if (argument.Key.Equals("Value"))
{
Application.Current.Dispatcher.Invoke(
() =>
{
existingVariable.VariableValue.Clear();
existingVariable.VariableValue.Add(
argument.Value.ToString());
});
}
}
}
}
}
}
}
我的脸还是有点难看。在检查 Assign activity 的参数时,我得到了键 "Value"。但是,如果我定义了一个名为 "i" 的变量,并希望在执行此 Assign 时看到它的变化,我必须查看 VisualBasicReference<> 以检查在那里声明的变量的名称,就像上面的代码一样。这种方法确实有效,我设法涵盖了目前还不错的整数和字符串..但是我的代码中是否有任何快捷方式可以使用?
编辑 2 我今天有了一个新想法并付诸实践:
这里是库代码:
public sealed class CustomAssign : NativeActivity, IActivityTemplateFactory
{
[Browsable(false)]
public Activity Body { get; set; }
protected override void Execute(NativeActivityContext context)
{
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete));
}
/// <summary>
/// Called from Execute when Condition evaluates to true.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="instance">The instance.</param>
public void OnExecuteComplete(NativeActivityContext context, ActivityInstance instance)
{
//to be added
}
Activity IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
{
return new CustomAssign
{
Body = new Assign()
};
}
}
以及设计师:
<sap:ActivityDesigner x:Class="ARIASquibLibrary.Design.CustomAsignDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
xmlns:statements="http://schemas.microsoft.com/netfx/2009/xaml/activities" Collapsible="False" BorderThickness="20" BorderBrush="Transparent">
<sap:ActivityDesigner.Template>
<ControlTemplate TargetType="sap:ActivityDesigner">
<Grid>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</sap:ActivityDesigner.Template>
<DockPanel LastChildFill="True">
<sap:WorkflowItemPresenter Item="{Binding Path=ModelItem.Body, Mode=TwoWay}"/>
</DockPanel>
</sap:ActivityDesigner>
所以,简而言之:我在我的自定义 activity 中托管了 Assign activity 并更改了 ControlTemplate 以仅保留 ContentPresenter,而 ContentPresenter 又将成为 Assign .现在,通过将其拖到设计器中,您将拥有完全相同的原始外观,但可以编写代码并检查执行步骤:
protected override void Execute(NativeActivityContext context)
或
public void OnExecuteComplete(NativeActivityContext context, ActivityInstance instance)
这是为什么?通过context.DataContext可以得到这个activity所在作用域内的所有变量和参数,以便开发watchwindow.
无需处理每个变量类型,只需将表达式转换为其基接口即可。
ITextExpression vbr = ass.To.Expression as ITextExpression;
然后您可以只访问表达式文本 属性,而不用关心分配给表达式的变量类型。
GlobalFunctions.WatchWindowViewModel.VariableDefinition existingVariable = GlobalFunctions.WatchWindowViewModel.Instance.VariableExists(vbr.ExpressionText);
这应该适合(我希望)所有可以应用的变量类型。