使用Baml2006Reader从baml加载ResourceDictionary

时间:2013-07-25 14:24:59

标签: wpf baml baml2006reader

如何使用ResourceDictionaory读取包含Baml2006Reader的baml流,而无需实际验证ResourceDictionary

我可以通过常规的baml准备好只包含UserControl,我可以使用Baml2006Reader.NodeType等检查XAML树。

但是,一旦读者点击了ResourceDictionaryBaml2006Reader.Member.Name就是"DeferrableContent"Baml2006Reader.Value包含MemoryStream无法被另一个{{1}实例解析1}}。我不能事件实例化读者:

  

发生System.IO.EndOfStreamException HResult = -2147024858
  消息=无法读取超出流的末尾。来源= mscorlib程序   堆栈跟踪:          在System.IO.MemoryStream.InternalReadInt32()          在System.Windows.Baml2006.Baml2006Reader.Process_Header()          at WpfApplication10.AssemblyExtensions.Read(Stream stream,List`1 result)in d:\ Documents \ Visual Studio   2012 \项目\ WpfApplication10 \ WpfApplication10 \ AssemblyExtensions.cs:行   84 InnerException:

1 个答案:

答案 0 :(得分:1)

似乎只要Baml2006Reader遇到Baml2006Reader.Member.Name"DeferrableContent"的元素,就会出现BamlReader.ValueMemoryStream的另一个节点。看来这个流只包含一个baml片段,并且没有标题(这就是System.Windows.Baml2006.Baml2006Reader.Process_Header()失败的原因。)

因此我们需要告诉baml读者读取baml片段。这可以通过向读者提供System.Windows.Baml2006.Baml2006ReaderSettings IsBamlFragment属性为true的实例来完成。

不幸的是,Baml2006ReaderSettings类和Baml2006Reader的相应构造函数都是内部的。所以我们需要求助于反思:

private static string PresentationFrameworkAssemblyName = "PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";

private static Baml2006Reader CreateBamlFragmentReader(MemoryStream substream, XamlSchemaContext schemaContext)
{
    var bamlSettingsType =
        Type.GetType(
            "System.Windows.Baml2006.Baml2006ReaderSettings, " + PresentationFrameworkAssemblyName);
    var settingsCtor =
        bamlSettingsType.GetConstructor(Type.EmptyTypes);
    var bamlSettings = settingsCtor.Invoke(null);
    var isBamlFragmentProp = bamlSettingsType.GetProperty("IsBamlFragment",
                                                              BindingFlags.NonPublic |
                                                              BindingFlags.Instance);
    isBamlFragmentProp.SetValue(bamlSettings, true, null);

    var ctor = typeof (Baml2006Reader).GetConstructor(
        BindingFlags.Instance | BindingFlags.NonPublic,
        null,
        new[]
        {
            typeof (Stream),
            Type.GetType(
                "System.Windows.Baml2006.Baml2006SchemaContext, " + PresentationFrameworkAssemblyName),
                bamlSettingsType
            },
            null);

        return (Baml2006Reader)ctor.Invoke(new[] { substream, schemaContext, bamlSettings });
    }

用法:

var substream = reader.Value as MemoryStream;
if (substream != null)
{
    using (var subReader = CreateBamlFragmentReader(substream, reader.SchemaContext))
    {
        // continue reading with subReader
    }
}

我知道这是相当脆弱的代码和非常hackish,但是到底是什么 - 它适用于我(目前为止)!