使用ActivityFunc<>的活动设计器中的绑定错误

时间:2011-10-07 20:41:45

标签: wpf workflow-foundation-4

我很难让我的自定义活动设计师在工作流设计器中显示。我的活动包括一个活动功能,我已经找到了许多博客文章,其中涉及herehereherehere

自定义活动有ActivityFunc<>作为输入参数,我需要在设计器中将func公开为放置区域,用户可以在其中放置“内部”活动(àla TransactionScope)。

自定义活动是在XAML中创作的,func的声明如下所示:

<x:Property Name="CompletionTest" Type="ActivityFunc(sdscmt:DmeTask, sdsav:WfPatient, sdscmc:DmeClinicalElement, x:Boolean)" />

XAML还包含与InvokeFunc<>属性匹配的CompletionTest活动。

活动设计师遵循上面提到的博客文章中列出的建议。特别是,它会覆盖OnModelItemChanged以初始化CompletionTest属性:

if (this.ModelItem.Properties["CompletionTest"].Value == null)
{
    this.ModelItem.Properties["CompletionTest"].SetValue(
        new ActivityFunc<DmeTask, WfPatient, DmeClinicalElement, bool>()
        {
            Argument1 = new DelegateInArgument<DmeTask>
            {
                Name = "task"
            },
            Argument2 = new DelegateInArgument<WfPatient>
            {
                Name = "patient"
            },
            Argument3 = new DelegateInArgument<DmeClinicalElement>
            {
                Name = "element"
            },
            Result = new DelegateOutArgument<bool>
            {
                Name = "success"
            },
        });
}

设计师的XAML看起来像这样:

<sap:ActivityDesigner x:Class="SoftInfo.Dme.ServicesDme.Workflow.Design.PerformTaskDesigner" ... >
    <StackPanel>
        <sap:WorkflowItemPresenter AllowedItemType="{x:Type sa:Activity}" Background="Transparent" MinWidth="150" MinHeight="100" HintText="Drop the completion test here" Margin="5,5,5,5" Item="{Binding Path=ModelItem.CompletionTest.Handler, Mode=TwoWay}" />
    </StackPanel>
</sap:ActivityDesigner>

毕竟,每当我将自定义活动的实例放入工作流程时,我会得到一个标有“无法生成PerformTask视图”的红色框,我的设计师应该出现在该框中。框的工具提示表明设计师内发生了异常:

    System.Windows.Markup.XamlParseException: A 'Binding' cannot be set on the 'Item' property of type 'WorkflowItemPresenter'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.

我不明白我做错了什么。之前我曾多次使用WorkflowItemPresenter,这是我第一次遇到此绑定错误。

1 个答案:

答案 0 :(得分:0)

这是一种搞砸的方式来解决这个问题。错误可能不正确;内在的例外会告诉我下注的故事(对不起,在我今天工作的时候听“权力的游戏”)。

我实施IActivityTemplateFactory来配置我的活动代表:

public sealed class MyActivity: NativeActivity, IActivityTemplateFactory
{
    public const string ChildArgumentName = "theArgument";

    public ActivityFunc<object, bool> Child { get; set; }

    Activity IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
    {
        return new MyActivity()
        {
            Child = new ActivityFunc<Capture, bool>
            {
                Argument = new DelegateInArgument<object>(ChildArgumentName )
            }
        };
    }
}

请注意这里有几件事。是的,设计界面实例化了一个Activity的实例,只是用它来创建同一个Activity的另一个实例(当然配置得当),但这个方法是防弹的。如果要求,您可以将IATF的实施移至其他地方,但如果谁关心并不重要?

请注意,我在Activity的设计中声明了Func参数的名称。您可以以更通用的方式(自定义属性等)执行此操作,但如果您的活动以可预测的方式组合在一起,我发现这是自动将子活动与其父项连接起来的最简单方式。 YMMV。

在设计师中,它的相似之处在于:

<sap:WorkflowItemPresenter
    HintText="Add child here"
    Item="{Binding ModelItem.Child.Handler}" />

这就是你所需要的一切。如果活动的签名不匹配,则不适合。孩子还利用IATF将自己绑定到其父级:

public sealed class ChildActivity : NativeActivity<bool>, IActivityTemplateFactory
{
    public InArgument<object> Target { get; set; }

    Activity IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
    {
        return new ChildActivity
        {
            Target = new VisualBasicValue<object>(MyActivity.ChildArgumentName)
        };
    }
 }

如果您希望将您的子Activity放在不同的目标上,您可能需要对target DependencyObject进行一些烦人的检查,这将允许您检查当前的工作流树。 (请注意,我不是100%熟悉VisualBasicValue的隐式转换行为,因此上面的代码可能会有一些编译器错误!)

另一个选择是,如果你必须特别棘手(从工具箱中删除一个Activity,然后将它拖到你必须重新进行检查的其他地方)就是从CacheMetadata中检查工作流的当前状态。我没有这样做,但我相信您可以使用设计图面更新您的注册,以反映工作流程的当前状态。