如何使用ResourceDictionaory
读取包含Baml2006Reader
的baml流,而无需实际验证ResourceDictionary
?
我可以通过常规的baml准备好只包含UserControl,我可以使用Baml2006Reader.NodeType
等检查XAML树。
但是,一旦读者点击了ResourceDictionary
,Baml2006Reader.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:
答案 0 :(得分:1)
似乎只要Baml2006Reader遇到Baml2006Reader.Member.Name
为"DeferrableContent"
的元素,就会出现BamlReader.Value
为MemoryStream
的另一个节点。看来这个流只包含一个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,但是到底是什么 - 它适用于我(目前为止)!