如何替换XpsDocumentWriter中的默认XamlWriter?

时间:2015-09-08 22:35:51

标签: c# wpf xaml xps xamlwriter

这是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

所以我想要做的是改变VisualsCollat​​or在序列化为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。

所以到目前为止,我没有解决方案。

未完成的潜在XamlWriter

如果可以替换序列化程序,那么我在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}}

0 个答案:

没有答案