自定义活动设计器中的参数验证 [英] Argument validation in custom activity designer

查看:115
本文介绍了自定义活动设计器中的参数验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使验证在设计器中正常工作以进行自定义活动时遇到问题。重现此行为的最简单示例如下:

I am having problems getting validation to work properly in the designer for my custom activity. The simplest sample to reproduce the behavior is as follows:

我有一个自定义WF4活动,并在字典中动态存储了参数:

I have a custom WF4 activity with a dynamic collection of arguments stored in a dictionary:

[Designer(typeof(DictionaryActivityDesigner))]
public class DictionaryActivity : NativeActivity
{
    [Browsable(false)]
    public Dictionary<string, InArgument> Arguments { get; set; }
    public InArgument<string> StringArg { get; set; }

    public DictionaryActivity()
    {
        Arguments = new Dictionary<string, InArgument>();
    }

    protected override void Execute(NativeActivityContext context)
    { }
}

在设计器中,我以动态方式创建用于编辑这些参数的表达式文本框。用户可以在单独的模态窗口中定义参数及其类型,但是为了简单起见,我在此示例中固定了参数:

In the designer I dinamically create expression text boxes for editing these arguments. The user has the possibility to define the arguments and their types in a separate modal window, but for the sake of simplicity I have fixed the arguments in this sample:

public partial class DictionaryActivityDesigner
{
    private Dictionary<string, Type> definition;

    public DictionaryActivityDesigner()
    {
        definition = new Dictionary<string, Type>
        {
            { "String Arg", typeof(string) },
            { "Int Arg", typeof(int) }
        };

        InitializeComponent();
    }

    public void InitializeGrid(Dictionary<string, Type> arguments)
    {
        ArgumentsGrid.RowDefinitions.Clear();
        ArgumentsGrid.Children.Clear();

        int gridRow = 0;
        foreach (var arg in arguments)
        {
            ArgumentsGrid.RowDefinitions.Add(new RowDefinition());

            var label = new Label()
            {
                Content = arg.Key + ":"
            };
            Grid.SetRow(label, gridRow);
            Grid.SetColumn(label, 0);
            ArgumentsGrid.Children.Add(label);

            var textbox = new ExpressionTextBox()
            {
                ExpressionType = arg.Value,
                OwnerActivity = ModelItem,
                UseLocationExpression = false
            };
            var binding = new Binding()
            {
                Mode = BindingMode.TwoWay,
                Converter = new ArgumentToExpressionConverter(),
                ConverterParameter = "In",
                Path = new PropertyPath("ModelItem.Arguments[(0)]", arg.Key)
            };
            textbox.SetBinding(ExpressionTextBox.ExpressionProperty, binding);
            Grid.SetRow(textbox, gridRow);
            Grid.SetColumn(textbox, 1);
            ArgumentsGrid.Children.Add(textbox);

            gridRow++;
        }
    }

    private void ActivityDesigner_Loaded(object sender, RoutedEventArgs e)
    {
        InitializeGrid(definition);
    }
}

以下是设计者的XAML:

Below is the XAML for the designer:

<sap:ActivityDesigner x:Class="ActivityValidation.DictionaryActivityDesigner"
                      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                      xmlns:s="clr-namespace:System;assembly=mscorlib"
                      xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
                      xmlns:sapc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation"
                      xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
                      Loaded="ActivityDesigner_Loaded">
    <sap:ActivityDesigner.Resources>
        <ResourceDictionary>
            <sapc:ArgumentToExpressionConverter x:Key="ArgumentToExpressionConverter" />
        </ResourceDictionary>
    </sap:ActivityDesigner.Resources>
    <StackPanel Orientation="Vertical">
        <Grid Name="ArgumentsGrid">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition MinWidth="250" />
            </Grid.ColumnDefinitions>
        </Grid>
        <sapv:ExpressionTextBox ExpressionType="s:String" 
                                OwnerActivity="{Binding ModelItem}" 
                                Expression="{Binding ModelItem.StringArg, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}" />
    </StackPanel>
</sap:ActivityDesigner>

InitializeGrid 方法添加表达式文本框 ArgumentGrid 的参数。在它下面,我有一个单独的静态定义的表达式文本框,用于在活动中的固定参数上演示(几乎)所需的行为。

The InitializeGrid method adds the expression text boxes for the arguments to the ArgumentGrid. Under it I have a separate statically defined expression text box for a fixed argument in the activity to demonstrate the (almost) desired behavior.

现在解决问题:


  1. 动态参数的无效表达式只会导致错误图标出现在文本框旁边,但不会传播到文本框的顶部

  1. Invalid expressions for the dynamic arguments only cause the error icon to appear beside the text box but it doesn't propagate to the top bar of the designer as it does if there is an error in the statically defined text box.

如果我在这种无效状态下关闭了设计器(并保存了定义) ,即使错误仅出现在动态文本框中,错误图标也会正确传播到顶部栏。尽管此后行为变得更加奇怪。在更改了参数的值之后,现在即使文本框旁边的错误图标也不再能始终如一地工作。

If I close the designer in such invalid state (and save the definition), the eror icon correctly propagates to the top bar even if the error is only in the dynamic text box. Though the behavior gets even more strange afterwards. After changing the values for the arguments, now even the error icon beside the text box doesn't work consistently any more.

如果我删除a的内容完全是动态文本框,字典中的值将设置为null,这在工作流定义中显示为< x:Null x:Key = String Arg /> 而不是< InArgument x:TypeArguments = x:String x:Key = String Arg> [ a]< / InArgument> 或只是省略与第一次编辑表达式之前的情况相同。如果我重新打开这样的工作流程,即使是静态创建的文本框也无法正常工作(错误图标仅在文本框处于焦点状态时才可见,并且不再传播到顶部)。

If I delete the contents of a dynamic text box completely, the value in the dictionary gets set to null which manifests in the workflow definition as <x:Null x:Key="String Arg" /> instead of <InArgument x:TypeArguments="x:String" x:Key="String Arg">["a"]</InArgument> or just ommiting the entry as is the case before editing the expression for the first time. If I reopen such a workflow even the statically created text box doesn't work properly any more (the error icon is only visible when text box is focused and it doesn't propagate to the top any more).

似乎在创建动态文本框时出现了错误。正确的做法是什么?有没有可用的示例为具有动态参数数量的自定义活动创建设计器?

It seems obvious that I am doing something wrong when creating the dynamic text boxes. What would be the correct way of doing it? Is there any example available for creating a designer for a custom activity with dynamic number of arguments?

EDIT:

对于那些感兴趣的人:

  • There was some more discussion on MSDN Forums where I have also posted the issue.
  • As a result of that discussion, I've also filed a report on Microsoft Connect.

推荐答案

在尝试为活动中的参数的动态集合创建设计器时遇到我在此描述的问题。我设法通过使用内置的 DynamicArgumentDialog 窗口。我必须重组活动以接受输入和输出参数的单个集合:

I encountered the problem I described here while trying to create a designer for a dynamic collection of arguments in an activity. I managed to work around the problem by using the built-in DynamicArgumentDialog window. I had to restructure my activity to accept a single collection of both input and output arguments:

public Dictionary<string, Argument> Arguments { get; set; }

而不是我以前使用的两个单独的集合:

instead of two separate collections I was using before:

public Dictionary<string, InArgument> InArguments { get; set; }
public Dictionary<string, OutArgument> OutArguments { get; set; }

我找到了用于调用基于XAML的子工作流的自定义活动在完成这项工作时非常有用。

I found the Custom Activity to Invoke XAML Based Child Workflows very helpful when making this work.

这篇关于自定义活动设计器中的参数验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆