2011-05-09 7 views
5

Tengo problemas para que la validación funcione correctamente en el diseñador para mi actividad personalizada. La muestra más sencilla de reproducir el comportamiento es el siguiente:Validación de argumentos en el diseñador de actividades personalizadas

tengo una actividad WF4 personalizada con una colección dinámica de los argumentos almacenados en un diccionario:

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

En el diseñador de I dinámicamente crear cuadros de texto de expresión para la edición estos argumentos El usuario tiene la posibilidad de definir los argumentos y sus tipos en una ventana modal por separado, pero en aras de la simplicidad que han fijado los argumentos de esta muestra:

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); 
    } 
} 

A continuación se muestra el código XAML para el diseñador:

<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> 

El método InitializeGrid agrega los cuadros de texto de expresión para los argumentos al ArgumentGrid. Debajo tengo un cuadro de texto de expresión separado estáticamente separado para un argumento fijo en la actividad para demostrar el comportamiento (casi) deseado.

Ahora para los problemas:

  1. expresiones no válidos para los argumentos dinámicos única causa el icono de error que aparezca al lado del cuadro de texto pero no se propaga a la barra superior del diseñador como si lo hace hay un error en el cuadro de texto definido estáticamente.

  2. Si cierro el diseñador en ese estado no válido (y guardo la definición), el icono de eror se propaga correctamente a la barra superior incluso si el error está solo en el cuadro de texto dinámico. Aunque el comportamiento se vuelve aún más extraño después. Después de cambiar los valores de los argumentos, ahora incluso el icono de error al lado del cuadro de texto ya no funciona de manera consistente.

  3. Si elimino el contenido de un cuadro de texto dinámico completo, el valor en el diccionario se establece en nulo que se manifiesta en la definición de flujo de trabajo como <x:Null x:Key="String Arg" /> en lugar de <InArgument x:TypeArguments="x:String" x:Key="String Arg">["a"]</InArgument> o simplemente ommiting la entrada como es el caso antes de editar la expresión por primera vez. Si vuelvo a abrir dicho flujo de trabajo, incluso el cuadro de texto creado estáticamente ya no funciona correctamente (el icono de error solo está visible cuando el cuadro de texto está enfocado y ya no se propaga hacia la parte superior).

Parece obvio que estoy haciendo algo mal al crear cuadros de texto dinámicos. ¿Cuál sería la forma correcta de hacerlo? ¿Hay algún ejemplo disponible para crear un diseñador para una actividad personalizada con un número dinámico de argumentos?

EDIT:

Para los interesados:

+0

Espera, ¿no estás haciendo la validación en cada llamada a CacheMetadata? Ese es el único lugar donde puede hacer validaciones en su Actividad y hacer que los errores/advertencias se propaguen por el flujo de trabajo. – Will

+0

@Will podría agregar errores de validación y advertencias en CacheMetadata, pero ExpressionTextBox tiene su propia validación incorporada que muestra el icono de error al lado del cuadro de texto si la expresión ingresada no es válida. No quisiera volver a implementar esa validación y no sé cómo podría acceder a esa funcionalidad de validación desde CacheMetadata para propagarla yo mismo agregando un error de validación. Además: la propagación parece funcionar bien siempre que evite colecciones de argumentos. –

Respuesta

4

He encontrado el problema que describí aquí al intentar crear un diseñador para una colección dinámica de argumentos en una actividad.Me las arreglé para solucionar el problema utilizando la ventana incorporada DynamicArgumentDialog. Tenía que reestructurar mi actividad a aceptar un único conjunto de los dos argumentos de entrada y de salida:

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

en lugar de dos colecciones separadas que estaba usando antes:

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

encontré el Custom Activity to Invoke XAML Based Child Workflows muy útil al hacer este trabajo.

Cuestiones relacionadas