2011-05-09 43 views
5

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

我有存储在一个字典参数的动态集合的自定义WF4活动:

[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) 
    { } 
} 

在设计师,我dinamically创建编辑表达式文本框这些论点。用户必须限定在一个单独的模式窗口的参数和它们的类型的可能性,但为了简单起见,我有固定的这个样品中的参数:

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:

<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。在它下面,我有一个单独的静态定义表达式文本框,用于演示活动中的固定参数以演示(几乎)所需的行为。

现在的问题:

  1. 无效表达式的动态参数只能导致错误的图标来显示文本框旁边,但它不会传播到因为它如果设计师的顶栏静态定义的文本框中有错误。

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

  3. 如果我删除一个动态文本框完全,在字典中的值被设置为空在工作流定义,其表现为<x:Null x:Key="String Arg" />,而不是<InArgument x:TypeArguments="x:String" x:Key="String Arg">["a"]</InArgument>或只是ommiting的条目是编辑表达式之前的情况下的内容首次。如果我重新打开这样的工作流程,即使静态创建的文本框不能再正常工作(错误图标仅在文本框聚焦时才可见,并且不会再传播到顶部)。

看起来很明显,我在创建动态文本框时做了一些错误。什么是正确的做法?是否有任何示例可用于使用动态数量的参数为自定义活动创建设计器?

编辑:

对于那些有兴趣:

+0

等一下,你不是在每次调用CacheMetadata时都进行验证吗?这是关于您可以对活动进行验证并将错误/警告传播到工作流程的唯一地方。 – Will 2011-05-10 14:47:55

+0

@我可以在CacheMetadata中添加验证错误和警告,但是ExpressionTextBox具有自己的内置验证,如果输入的表达式无效,将在文本框旁边显示错误图标。我不想重新实现验证,我不知道如何从CacheMetadata中访问验证功能,通过添加验证错误来自行传播验证功能。此外:传播似乎工作得很好,只要我避免收集参数。 – 2011-05-10 19:45:17

回答

4

我遇到了我在这里描述的问题,同时尝试为活动中的动态参数集合创建一个设计器。我设法通过使用内置的DynamicArgumentDialog窗口来解决这个问题。我不得不调整自己的行为接受的输入和输出参数的单个集合:

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

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

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

我发现Custom Activity to Invoke XAML Based Child Workflows非常有帮助制作时这项工作。