リホスティングしているワークフローデザイナーで、デザインした内容を保存する場合には WorkflowDesigner クラスの Save メソッドを呼び出します。しかし、条件ははっきりしていないのですが保存時にぬるぽな Exception が発生する事があります。
これは WF の、というよりも XAML を扱うもの共通で関わる問題なのですが、XAML の解析において正常に解析・解決できないケースがあるということです。その際は XML 名前空間プレフィックスの解決に失敗しインスタンスを生成しようとしたんだけどできなかった、というような形でぬるぽ例外が発生してしまうとのことです。
対応策としては、明示的に「XAML プロセッサで無視してよい」という指定を XAML 上に追加する必要があります。その際に必要となるのが mc:Ignorable 属性です。これを元にWorkflowDesinger.Save 呼び出し時に mc:Ignorable 属性を付与する方法が海外 MSDN Blog に記載されていましたので、それを VB 用に移植したものを紹介します。Blog にて紹介されている IgnorableXamlWrite クラスを用意し、WorkflowDesignerで保存する前に XAML 上に mc:Ignorable 属性を付与するようにします。
1: Imports System.Collections.Generic2: Imports System.IO3: Imports System.Xaml4: Imports System.Xml5:6: Public Class IgnorableXamlXmlWriter7: Inherits XamlXmlWriter8:9: Private ignorableNamespaces As New HashSet(Of NamespaceDeclaration)()10: Private allNamespaces As New HashSet(Of NamespaceDeclaration)()11: Private objectWritten As Boolean12: Private hasDesignNamespace As Boolean13: Private designNamespacePrefix As String14:15: Public Sub New(ByVal tw As TextWriter, ByVal context As XamlSchemaContext)16: MyBase.new(XmlWriter.Create(tw, New XmlWriterSettings With {.Indent = True, .OmitXmlDeclaration = True}),17: context,18: New XamlXmlWriterSettings With {.AssumeValidInput = True})19: End Sub20:21: Public Overrides Sub WriteNamespace(ByVal namespaceDeclaration As System.Xaml.NamespaceDeclaration)22: If Not objectWritten Then23: allNamespaces.Add(namespaceDeclaration)24: If namespaceDeclaration.Namespace = "http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" Then25: hasDesignNamespace = True26: designNamespacePrefix = namespaceDeclaration.Prefix27: End If28: End If29: MyBase.WriteNamespace(namespaceDeclaration)30: End Sub31:32: Public Overrides Sub WriteStartObject(ByVal type As System.Xaml.XamlType)33: If Not objectWritten Then34: If hasDesignNamespace Then35: Dim mcAlias = "mc"36: WriteNamespace(New NamespaceDeclaration("http://schemas.openxmlformats.org/markup-compatibility/2006", mcAlias))37: End If38: End If39: MyBase.WriteStartObject(type)40:41: If Not objectWritten Then42: If hasDesignNamespace Then43: Dim ign As New XamlDirective("http://schemas.openxmlformats.org/markup-compatibility/2006", "Ignorable")44: WriteStartMember(ign)45: WriteValue(designNamespacePrefix)46: WriteEndMember()47: objectWritten = True48: End If49: End If50: End Sub51:52: End Class53:
上記のような形で IgonorableXamlXmlWriter クラスとして用意した次には、このように利用して保存を行います。
1: Dim mdlTree = designer.Context.Services.GetService(Of Model.ModelTreeManager).Root2: Dim sb As New StringBuilder3: Dim xsc = New XamlSchemaContext4: Dim bw = ActivityXamlServices.CreateBuilderWriter(New IgnorableXamlXmlWriter(5: New StringWriter(sb),6: xsc))7:8: XamlServices.Save(bw, mdlTree.GetCurrentValue)9: designer.Save("tempWF.xaml")
このようにすることで、WorkflowDesigner が保存を行う際に Ignorable 属性が付与した形で保存されるようになります。流れとしては次のようになります。
その時点でデザイナ上に展開されている内容を取得し、ActivityXamlServices クラスを利用してアクティビティの内容を表すインスタンスを生成します。ActivityXamlServices.CreateBuilderWriter メソッドで生成されたインスタンスに書き込む事ができ、その際に利用する Writer クラスを指定し呼び出します。呼び出す事で、指定した Writer クラスにてアクティビティの XAML を生成する処理が行われますので、その内容を XamlServices.Save メソッドにて保存、WorkflowDesigner 側へと反映させます。その後に WorkflowDesigner.Save メソッドを呼ぶことで、Ignorable 属性が付与した形にてファイルに保存する事ができます。
このように書くと何が何だかわからなくなりそうなので、デザイナから保存する場合はこういうおまじないが必要!、という程度でも構わないですw
0 件のコメント:
コメントを投稿