这是XamlWriter.Save
非常慢的已知问题(只有Google" xamlwriter slow")。我编写的应用程序生成XPS文档,并且它使用的元素范围有限。因此,我想用更高效的XamlWriter
替换XamlWriter
。是否可以替换XpsDocumentWriter
使用的默认XpsDocument
?
以下是XpsDocumentWriter如何序列化为Xaml。
这就是我写给var writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
var vc = writer.CreateVisualsCollator();
vc.BeginBatchWrite();
foreach (var pfe in pageFrameworkElements) {
vc.Write(pfe);
}
vc.EndBatchWrite();
的方式:
VisualsCollator
所以我想要做的是改变VisualsCollator在序列化为Xaml时使用的序列化程序。
VisualsToXpsDocument
实际上是// Generated by .NET Reflector from C:\Windows\Microsoft.Net\assembly\GAC_64\System.Printing\v4.0_4.0.0.0__31bf3856ad364e35\System.Printing.dll
namespace System.Windows.Xps
{
/* Removed Code */
public class VisualsToXpsDocument : SerializerWriterCollator
{
/* Removed Code */
[SecurityCritical]
private PackageSerializationManager _manager;
/* Removed Code */
[return: MarshalAs(UnmanagedType.U1)]
[SecuritySafeCritical]
private unsafe bool WriteVisual([MarshalAs(UnmanagedType.U1)] bool asyncMode, PrintTicket printTicket, PrintTicketLevel printTicketLevel, Visual visual)
{
/* Removed Code */
if (!asyncMode)
{
try
{
try
{
this._manager.SaveAsXaml(visual); /* This line is called to serialize to Xaml */
return flag;
}
catch (PrintingCanceledException exception)
{
this.parentWriter.OnWritingCanceled(this, exception);
}
return flag;
}
finally
{
flag = true;
}
}
XpsWriterException.ThrowException("XPSWriter.BatchSync");
return flag;
}
}
}
:
PackageSerializationManager _manager
而XpsSerializationManager
实际上是// Generated by .NET Reflector from C:\Windows\Microsoft.Net\assembly\GAC_MSIL\ReachFramework\v4.0_4.0.0.0__31bf3856ad364e35\ReachFramework.dll
namespace System.Windows.Xps.Serialization
{
/* Removed Code */
public class XpsSerializationManager : PackageSerializationManager
{
/* Removed Code */
private ReachHierarchySimulator _simulator;
/* Removed Code */
internal override ReachSerializer GetSerializer(object serializedObject)
{
ReachSerializer serializer = null;
serializer = base.GetSerializer(serializedObject);
if (serializer == null)
{
serializer = base.SerializersCacheManager.GetSerializer(serializedObject);
}
return serializer;
}
/* Removed Code */
public override void SaveAsXaml(object serializedObject)
{
/* Removed Code */
ReachSerializer serializer = this.GetSerializer(serializedObject);
if (serializer == null)
{
throw new XpsSerializationException(System.Windows.Xps.SR.Get("ReachSerialization_NoSerializer"));
}
serializer.SerializeObject(serializedObject);
/* Removed Code */
}
/* Removed Code */
}
}
:
// Generated by .NET Reflector from C:\Windows\Microsoft.Net\assembly\GAC_MSIL\ReachFramework\v4.0_4.0.0.0__31bf3856ad364e35\ReachFramework.dll
namespace System.Windows.Xps.Serialization
{
/* Removed Code */
public abstract class PackageSerializationManager : IDisposable
{
/* Removed Code */
private System.Windows.Xps.Serialization.SerializersCacheManager _serializersCacheManager;
/* Removed Code */
internal virtual ReachSerializer GetSerializer(object serializedObject)
{
return this._serializersCacheManager.GetSerializer(serializedObject);
}
/* Removed Code */
public abstract void SaveAsXaml(object serializedObject);
/* Removed Code */
internal System.Windows.Xps.Serialization.SerializersCacheManager CacheManager
{
get
{
return this._serializersCacheManager;
}
}
/* Removed Code */
internal System.Windows.Xps.Serialization.SerializersCacheManager SerializersCacheManager
{
get
{
return this._serializersCacheManager;
}
}
}
}
这是它继承的PackageSerializationManager:
XpsSerializationManager
我正在考虑从SaveAsXaml
继承并覆盖PackageSerializationManager _manager
方法,但我不确定如何实际覆盖它,因为它没有返回值或提供流或任何要写入的对象。即使我这样做了,我也必须使用反射来更改VisualsToXpsDocument
类中的XamlWriter
字段,所以它有点hacky。
所以到目前为止,我没有解决方案。
如果可以替换序列化程序,那么我在here找到自定义using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Markup;
using System.Windows.Markup.Primitives;
using System.Xml;
// Summary:
// Provides a single static Overload:SXamlWriter.Save method
// that can be used for limited Extensible Application
// Markup Language (XAML) serialization of provided runtime objects. This class
// cannot be inherited, and only has static methods.
public static class XamlWriter {
// Summary:
// Returns a Extensible Application Markup Language (XAML) string that serializes
// the provided object.
//
// Parameters:
// obj:
// The element to be serialized. Typically, this is the root element of a page
// or application.
//
// Returns:
// Extensible Application Markup Language (XAML) string that can be written
// to a stream or file. The logical tree of all elements that fall under the
// provided obj element will be serialized.
//
// Exceptions:
// System.Security.SecurityException:
// the application is not running in full trust.
//
// System.ArgumentNullException:
// obj is null.
public static string Save(object obj) {
var sb = new StringBuilder();
WriteObject(obj, sb, true);
return sb.ToString();
}
//WriteObject - 3 params (used primarily when isRoot is true or by the 2 param version)
private static void WriteObject(object obj, StringBuilder sb, bool isRoot) {
WriteObjectWithKey(null, obj, sb, isRoot);
}
//WriteObject - 2 param version
private static void WriteObject(object obj, StringBuilder sb) {
WriteObjectWithKey(null, obj, sb, false);
}
//WriteObject - 3 param version
private static void WriteObjectWithKey(object key, object obj, StringBuilder sb) {
WriteObjectWithKey(key, obj, sb, false);
}
private static Dictionary<Type, string> contentProperties = new Dictionary<Type, string>();
//WriteObject - 4 params (used primarily when isRoot is true or by the 3 param version)
private static void WriteObjectWithKey(object key, object obj, StringBuilder sb, bool isRoot) {
var propertyElements = new List<MarkupProperty>();
//If the value is a string
var s = obj as string;
if (s != null) {
//TODO: in a dictionary, this should be serialized as a <s:String />
sb.Append(s);
return;
}
MarkupProperty contentProperty = null;
string contentPropertyName = null;
var markupObj = MarkupWriter.GetMarkupObjectFor(obj);
var objectType = obj.GetType();
sb.Append("<" + markupObj.ObjectType.Name);
if (isRoot) {
sb.Append(
" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"");
}
if (key != null) {
var keyString = key.ToString();
if (keyString.Length > 0)
sb.Append(" x:Key=\"" + keyString + "\"");
else
//TODO: key may not be a string, what about x:Type...
throw new NotImplementedException("Sample XamlWriter cannot yet handle keys that aren't strings");
}
//Look for CPA info in our cache that keeps contentProperty names per Type
//If it doesn't have an entry, go get the info and store it.
if (!contentProperties.ContainsKey(objectType)) {
var lookedUpContentProperty = string.Empty;
foreach (Attribute attr in markupObj.Attributes) {
var cpa = attr as ContentPropertyAttribute;
if (cpa != null)
lookedUpContentProperty = cpa.Name;
}
contentProperties.Add(objectType, lookedUpContentProperty);
}
contentPropertyName = contentProperties[objectType];
var contentString = string.Empty;
foreach (var markupProperty in markupObj.Properties) {
if (markupProperty.Name != contentPropertyName) {
if (markupProperty.IsValueAsString)
contentString = markupProperty.Value as string;
else if (!markupProperty.IsComposite)
sb.Append(" " + markupProperty.Name + "=\"" + markupProperty.Value + "\"");
else if (markupProperty.Value.GetType() == typeof (NullExtension))
sb.Append(" " + markupProperty.Name + "=\"{x:Null}\"");
else {
propertyElements.Add(markupProperty);
}
}
else
contentProperty = markupProperty;
}
if (contentProperty != null || propertyElements.Count > 0 || contentString != string.Empty) {
sb.Append(">");
foreach (var markupProp in propertyElements) {
var propElementName = markupObj.ObjectType.Name + "." + markupProp.Name;
sb.Append("<" + propElementName + ">");
WriteChildren(sb, markupProp);
sb.Append("</" + propElementName + ">");
}
if (contentString != string.Empty)
sb.Append(contentString);
else if (contentProperty != null)
WriteChildren(sb, contentProperty);
sb.Append("</" + markupObj.ObjectType.Name + ">");
}
else {
sb.Append("/>");
}
}
private static void WriteChildren(StringBuilder sb, MarkupProperty markupProp) {
if (!markupProp.IsComposite) {
WriteObject(markupProp.Value, sb);
}
else {
var collection = markupProp.Value as IList;
var dictionary = markupProp.Value as IDictionary;
if (collection != null) {
foreach (var o in collection)
WriteObject(o, sb);
}
else if (dictionary != null) {
foreach (var key in dictionary.Keys) {
WriteObjectWithKey(key, dictionary[key], sb);
}
}
else
WriteObject(markupProp.Value, sb);
}
}
//
// Summary:
// Saves Extensible Application Markup Language (XAML) information into a provided
// stream to serialize the provided object.
//
// Parameters:
// obj:
// The element to be serialized. Typically, this is the root element of a page
// or application.
//
// stream:
// Destination stream for the serialized XAML information.
//
// Exceptions:
// System.Security.SecurityException:
// the application is not running in full trust.
//
// System.ArgumentNullException:
// obj is null -or- stream is null.
public static void Save(object obj, Stream stream) {
var writer = new StreamWriter(stream);
stream.Seek(0, SeekOrigin.Begin); //this line may not be needed.
writer.Write(Save(obj));
writer.Flush();
}
//
// Summary:
// Saves Extensible Application Markup Language (XAML) information as the source
// for a provided text writer object. The output of the text writer can then
// be used to serialize the provided object.
//
// Parameters:
// writer:
// TextWriter instance to use to write the serialized XAML information.
//
// obj:
// The element to be serialized. Typically, this is the root element of a page
// or application.
//
// Exceptions:
// System.ArgumentNullException:
// obj is null -or- writer is null.
//
// System.Security.SecurityException:
// the application is not running in full trust.
public static void Save(object obj, TextWriter writer) {}
//
// Summary:
// Saves Extensible Application Markup Language (XAML) information as the source
// for a provided XML writer object. The output of the XML writer can then be
// used to serialize the provided object.
//
// Parameters:
// obj:
// The element to be serialized. Typically, this is the root element of a page
// or application.
//
// xmlWriter:
// Writer to use to write the serialized XAML information.
//
// Exceptions:
// System.ArgumentNullException:
// obj is null -or- manager is null.
//
// System.Security.SecurityException:
// the application is not running in full trust.
public static void Save(object obj, XmlWriter xmlWriter) {}
}
的示例:
{{1}}