在为参数添加默认值时,重新托管的设计器(WF4)的结果会出现问题。其他所有情况似乎都很好。这是(几乎)空工作流程的(删节)xaml。
<Activity mc:Ignorable="sap" x:Class="{x:Null}" this:_b40c.NewArg="test" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities"
xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation"
xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:this="clr-namespace:" xmlns:twc="clr-namespace:Telogis.Workflow.CustomerApi;assembly=Telogis.Workflow.Activities"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Members>
<x:Property Name="AuthenticationHeader" Type="InArgument(twc:AuthenticationHeader)" />
<x:Property Name="BaseTdeUri" Type="InArgument(x:Uri)" />
<x:Property Name="NewArg" Type="InArgument(x:String)" />
</x:Members>
<sap:VirtualizedContainerService.HintSize>654,676</sap:VirtualizedContainerService.HintSize>
<mva:VisualBasic.Settings>Assembly references and imported namespaces serialized as XML namespaces</mva:VisualBasic.Settings>
<Flowchart />
</Activity>
特别是在添加默认值时,会对定义进行以下添加:this:_b40c.NewArg="test"
和xmlns:this="clr-namespace:"
xmlns:this="clr-namespace:"
无效,因为它不指向任何地方,无法使用ActivityXamlServices.Load(stream);
进行解析(它会抛出XamlObjectWriterException:“'无法设置未知成员'{clr-namespace:} _ b40c.NewArg'。' ...)
无论指定的参数类型是什么,这似乎都会发生。
知道可能导致这种情况的原因吗?
更新
我首先使用ActivityBuilder
来使用该活动。这很好,但由于我没有提供名称,因此必须生成一个密钥,在上面的示例_b40c
中。处理这些密钥时ActivityXamlServices.Load
有一些问题。但是,简单地定义ActivityBuilder
的名称似乎就可以了。
这仍然无法回答为什么它在没有实际名称空间的情况下创建xmlns:this="clr-namespace:"
。
答案 0 :(得分:0)
您的工作流程xaml无效。我不知道你在哪里或者它是如何进入这种状态的。
我可以说这是因为
<Activity
x:Class="{x:Null}"
this:_b40c.NewArg="test"
xmlns:this="clr-namespace:"
clr样式的名称空间声明无效。它应该读
clr-namespace:Some.Namespace.In.The.Current.Assembly
或
clr-namespace:Some.Namespace;assembly=SomeAssemblyWithSomeNamespace
由于您的声明格式错误,XamlObjectWriter无法解析此 xml命名空间,以确定您的_b40c
类型所在的命名空间/程序集。此外,这看起来非常可疑同样。我以前从未见过将x:Class
设置为null。这也让我感到不正常。
答案 1 :(得分:0)
如果我理解得很好 - 这是 WF Designer 错误。
当我必须在我的自定义WF设计器中支持InArgument<T>
的默认值定义时,我遇到了这个问题。我仍然对这个基本程序缺乏支持感到惊讶。
失败有两个原因:
{x:Null}
属性x:Class
的定义
xmlns:this
属性我通过介入XAML保存过程解决了这个问题:
打电话给
_workflowDesigner.Save(_editedFile);
我添加了这两行:
#region x:Class and Argument<T> default value issues solution
await CreateAttributeValue(_editedFile, ConstXClassAttributeName, typeof(App).Namespace + "." + Path.GetFileNameWithoutExtension(_editedFile));
//should finish first operation before second operation begins to avoid I/O exception
await CreateAttributeValue(_editedFile, ConstNamespaceAttributeName, ConstXamlClrNamespace + typeof(App).Namespace);
await RepairArgsAttributes(_editedFile);
#endregion
This is the methods definition:
/// <summary>
/// Reason of using of this method: bug in workflow designer. When you save your xaml file, WF Designer assign "{x:Null}" to x:Class attribute
/// Bug: In addition, if you want to set default value for your InArgument<T>, it defines attribute "this" (namespace declaration) with empty value. When you try to open your file, designer fails to parse XAML.
/// </summary>
/// <param name="editedFile"></param>
/// <param name="attribteName"></param>
/// <param name="attributeValueToReplace"></param>
private static async Task CreateAttributeValue(string editedFile, string attribteName, string attributeValueToReplace)
{
XmlDocument xmlDoc = new XmlDocument();
await Task.Run(() => xmlDoc.Load(editedFile));
await Task.Run(() =>
{
var attributteToReplace = xmlDoc.FirstChild.Attributes?[attribteName];
if (null != attributteToReplace)
{
xmlDoc.FirstChild.Attributes[attribteName].Value = attributeValueToReplace;
xmlDoc.Save(editedFile);
}
});
}
/// <summary>
/// Bug in Workflow designer: workflow designer saves declaration for In/Out Arguments in invalid format. Means, that it is unable to open the same file it saved itself. This method fixes the Arguments declaration in XAML xmlns
/// </summary>
/// <param name="editedFile"></param>
/// <returns></returns>
private async Task RepairArgsAttributes(string editedFile)
{
XmlDocument xmlDoc = new XmlDocument();
await Task.Run(() => xmlDoc.Load(editedFile));
await Task.Run(() =>
{
for (int i = 0; i < xmlDoc.FirstChild.Attributes.Count; i++)
{
if (xmlDoc.FirstChild.Attributes[i].Name.StartsWith(ConstInvalidArgStarts))
{
string innvalidAttrName = xmlDoc.FirstChild.Attributes[i].Name;//extraction of full argument declaration in xmlns
string[] oldStrings = innvalidAttrName.Split('.');//extraction of arguemnt name string
string localName = Path.GetFileNameWithoutExtension(editedFile) + "." + oldStrings[1];//build valid argment declaration without perfix
string valueBackup = xmlDoc.FirstChild.Attributes[i].Value;//saving of default value of Arguemnt<T>
xmlDoc.FirstChild.Attributes.RemoveNamedItem(xmlDoc.FirstChild.Attributes[i].Name);//removal of invalid Arguemnt declaration with default value. WARNING: when you remove attribue, at this moment you have another item at the place xmlDoc.FirstChild.Attributes[i]
//definition of new valid attribute requries: set separelly attribute prefix, localName (not "name" - it causes invalid attribute definition) and valid namespace url (in our case it's namespace deifinition in "this")
XmlAttribute attr = xmlDoc.CreateAttribute(ConstArgPrefix, localName, xmlDoc.FirstChild.Attributes[ConstNamespaceAttributeName].Value);
attr.Value = valueBackup;
xmlDoc.FirstChild.Attributes.InsertBefore(attr, xmlDoc.FirstChild.Attributes[i]);//define new correct Argument declaration attribute at the same place where was invalid attribute. When you put valid attribute at the same place your recover valid order of attributes that was changed while removal of invalid attribute declaration
}
}
xmlDoc.Save(editedFile);
});
}
常量定义是:
#region Constants
private const string ConstXClassAttributeName = "x:Class";
private const string ConstXamlClrNamespace = "clr-namespace:";
private const string ConstNamespaceAttributeName = "xmlns:this";
private const string ConstInvalidArgStarts = @"this:_";
private const string ConstArgPrefix = @"this";
#endregion
此解决方案也可以解决您的问题。