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:
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.
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.
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:
- Hubo algún debate más en los foros de MSDN donde también posted the issue tengo.
- Como resultado de esa discusión, también he presentado a report on Microsoft Connect.
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
@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. –