У меня возникают проблемы с правильной работой проверки в конструкторе для моей настраиваемой операции. Самый простой пример для воспроизведения поведения выглядит следующим образом:
У меня есть настраиваемое действие 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
. Под ним у меня есть отдельное текстовое поле статически определенного выражения для фиксированного аргумента в действии, чтобы продемонстрировать (почти) желаемое поведение.
Теперь о проблемах:
Недопустимые выражения для динамических аргументов вызывают только появление значка ошибки рядом с текстовым полем, но он не распространяется на верхнюю панель конструктора, как это происходит в случае ошибки в статически определенном текстовом поле.
Если я закрою конструктор в таком недопустимом состоянии (и сохраню определение), значок ошибки правильно распространяется на верхнюю панель, даже если ошибка находится только в динамическом текстовом поле. Хотя потом поведение становится еще более странным. После изменения значений аргументов теперь даже значок ошибки рядом с текстовым полем больше не работает последовательно.
Если я полностью удаляю содержимое динамического текстового поля, значение в словаре становится равным нулю, что проявляется в определении рабочего процесса как
<x:Null x:Key="String Arg" />
вместо<InArgument x:TypeArguments="x:String" x:Key="String Arg">["a"]</InArgument>
или просто опускается запись, как в случае, прежде чем редактировать выражение в первый раз. Если я снова открою такой рабочий процесс, даже статически созданное текстовое поле больше не будет работать должным образом (значок ошибки виден только тогда, когда текстовое поле сфокусировано, и оно больше не распространяется наверх).
Кажется очевидным, что я делаю что-то не так при создании динамических текстовых полей. Как правильно это сделать? Есть ли какой-нибудь пример создания дизайнера для настраиваемого действия с динамическим числом аргументов?
РЕДАКТИРОВАТЬ:
Для заинтересованных:
- На форумах MSDN было еще одно обсуждение, где у меня также есть опубликовал проблему.
- В результате этого обсуждения я также подал отчет о Microsoft Connect.