Проверка аргумента в конструкторе пользовательских действий - PullRequest
5 голосов
/ 10 мая 2011

У меня проблемы с получением проверки правильности работы в конструкторе для моей пользовательской активности.Простейший пример для воспроизведения поведения следующий:

У меня есть пользовательское действие 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)
    { }
}

В конструкторе я динамически создаю выражениетекстовые поля для редактирования этих аргументов.Пользователь имеет возможность определять аргументы и их типы в отдельном модальном окне, но для простоты я исправил аргументы в этом примере:

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. Если я закрою конструктор в таком недопустимом состоянии (и сохраню определение), значок ошибки корректно распространяется на верхнюю панель, даже если ошибка присутствует только в динамическом текстовом поле.Хотя потом поведение становится еще более странным.После изменения значений аргументов теперь даже значок ошибки рядом с текстовым полем перестает работать согласованно.

  3. Если я полностью удаляю содержимое динамического текстового поля,значение в словаре устанавливается равным нулю, что проявляется в определении рабочего процесса как <x:Null x:Key="String Arg" /> вместо <InArgument x:TypeArguments="x:String" x:Key="String Arg">["a"]</InArgument> или просто пропускает запись, как в случае до редактирования выражения в первый раз.Если я снова открою такой рабочий процесс, даже статически созданное текстовое поле больше не будет работать должным образом (значок ошибки отображается только тогда, когда текстовое поле находится в фокусе и больше не распространяется на верхнюю часть).

Кажется очевидным, что я делаю что-то не так при создании динамических текстовых полей.Каков будет правильный способ сделать это?Есть ли какой-нибудь пример для создания конструктора для пользовательского действия с динамическим числом аргументов?

РЕДАКТИРОВАТЬ:

Для тех, кто заинтересован:

1 Ответ

4 голосов
/ 02 августа 2011

Я столкнулся с проблемой, которую я описал здесь, при попытке создать конструктор для динамического набора аргументов в деятельности.Мне удалось обойти эту проблему с помощью встроенного окна DynamicArgumentDialog .Мне пришлось реструктурировать свою деятельность, чтобы принимать одну коллекцию входных и выходных аргументов:

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

вместо двух отдельных коллекций, которые я использовал ранее:

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

Я нашел1009 * Настраиваемое действие для запуска дочерних рабочих процессов на основе XAML очень полезно при выполнении этой работы.

...