0

如何在不实际实例化 the 的情况下阅读包含 aResourceDictionaory的baml 流?Baml2006ReaderResourceDictionary

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

但是一旦读者点击 a ResourceDictionary, Baml2006Reader.Member.Nameis"DeferrableContent"并且 Baml2006Reader.Value包含 aMemoryStream不能被Baml2006Reader. 我无法事件实例化阅读器:

System.IO.EndOfStreamException 发生 HResult=-2147024858
消息=无法读取超出流的末尾。Source=mscorlib StackTrace:在 System.IO.MemoryStream.InternalReadInt32() at System.Windows.Baml2006.Baml2006Reader.Process_Header() at WpfApplication10.AssemblyExtensions.Read(Stream stream, List`1 result) in d:\Documents\Visual Studio 2012\Projects\WpfApplication10\WpfApplication10\AssemblyExtensions.cs:第 84 行内部异常:

4

1 回答 1

1

似乎每当 Baml2006Reader 遇到一个元素 where Baml2006Reader.Member.Nameis"DeferrableContent"它后面跟着另一个节点 where BamlReader.Valueis a MemoryStream。似乎这个流只包含一个 baml 片段并且没有标头(这就是System.Windows.Baml2006.Baml2006Reader.Process_Header()失败的原因。)

所以我们需要告诉 baml 阅读器读取一个 baml 片段。这可以通过给读者一个属性System.Windows.Baml2006.Baml2006ReaderSettings所在的实例来完成。IsBamlFragmenttrue

不幸的是,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,但到底是什么 - 它有效(目前对我来说)!

于 2013-07-29T11:48:03.660 回答