File: Serialization\Manager\NGCSerializationManagerAsync.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\ReachFramework\ReachFramework.csproj (ReachFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Xml;
using System.IO;
using System.Security;
using System.ComponentModel.Design.Serialization;
using System.Windows.Xps.Packaging;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Markup;
using System.Printing;
using System.Windows.Threading;
using MS.Internal;
using Microsoft.Internal.AlphaFlattener;
 
 
//
// Ngc = Next Generation Converter. It means to convert the avalon element tree
//  to the downlevel GDI primitives.
//
namespace System.Windows.Xps.Serialization
{
    /// <summary>
    /// NgcSerializationManager is a class to help print avalon content (element tree) to traditional printer
    /// </summary>
    // [CLSCompliant(false)]
    internal sealed class NgcSerializationManagerAsync :
                          PackageSerializationManager
    {
        #region Constructor
 
        /// <summary>
        /// This constructor take PrintQueue parameter
        /// </summary>
        /// <exception cref="ArgumentNullException">queue is NULL.</exception>
        public
        NgcSerializationManagerAsync(
            PrintQueue   queue,
            bool         isBatchMode
            ):
        base()
        {
            ArgumentNullException.ThrowIfNull(queue);
            _printQueue                      = queue;
            _operationStack                  = new Stack();
            _isBatchMode                     = isBatchMode;
            _batchOperationQueue             = new Queue();
            _dispatcher                      = Dispatcher.CurrentDispatcher;
            _serializationOperationCanceled  = false;
            _isSimulating                    = false;
            _isBatchWorkItemInProgress       = false;
            _printTicketManager              = new NgcPrintTicketManager(_printQueue);
        }
 
        #endregion Construtor
 
        #region PackageSerializationManager override
 
        /// <summary>
        /// The function will serializer the avalon content to the printer spool file.
        /// SaveAsXaml is not a propriate name. Maybe it should be "Print"
        /// </summary>
        /// <exception cref="ArgumentNullException">serializedObject is NULL.</exception>
        /// <exception cref="XpsSerializationException">serializedObject is not a supported type.</exception>
        public
        override
        void
        SaveAsXaml(
            Object  serializedObject
            )
        {
            ArgumentNullException.ThrowIfNull(serializedObject);
 
            if (!IsSerializedObjectTypeSupported(serializedObject))
            {
                throw new XpsSerializationException(SR.ReachSerialization_NotSupported);
            }
 
            if(_isBatchMode && !_isSimulating)
            {
                XpsSerializationPrintTicketRequiredEventArgs printTicketEvent =
                new XpsSerializationPrintTicketRequiredEventArgs(PrintTicketLevel.FixedDocumentSequencePrintTicket,
                                                                 0);
                OnNGCSerializationPrintTicketRequired(printTicketEvent);
 
                StartDocument(null,false);
                _isSimulating = true;
            }
 
            if(!_isBatchMode &&
               IsDocumentSequencePrintTicketRequired(serializedObject))
            {
                XpsSerializationPrintTicketRequiredEventArgs printTicketEvent =
                new XpsSerializationPrintTicketRequiredEventArgs(PrintTicketLevel.FixedDocumentSequencePrintTicket,
                                                                 0);
                OnNGCSerializationPrintTicketRequired(printTicketEvent);
            }
 
            if(_isBatchMode)
            {
                //
                // Add the Visual received in to the queue
                //
                BatchOperationWorkItem  batchOperationWorkItem = new BatchOperationWorkItem(BatchOperationType.batchWrite,
                                                                                            serializedObject);
                _batchOperationQueue.Enqueue(batchOperationWorkItem);
                PostSerializationTask(new DispatcherOperationCallback(InvokeSaveAsXamlBatchWorkItem));
            }
            else
            {
                ReachSerializer reachSerializer = GetSerializer(serializedObject);
 
                if(reachSerializer != null)
                {
                    //
                    // Prepare the context that is going to be pushed on the stack
                    //
                    SerializationManagerOperationContextStack
                    contextStack = new SerializationManagerOperationContextStack(reachSerializer,
                                                                                 serializedObject);
                    //
                    // At this stage, start calling another method which would peak at the stack
                    //
                    _operationStack.Push(contextStack);
 
                    PostSerializationTask(new DispatcherOperationCallback(InvokeSaveAsXamlWorkItem));
                }
                else
                {
                    throw new XpsSerializationException(SR.ReachSerialization_NoSerializer);
                }
            }
        }
 
        internal
        Object
        InvokeSaveAsXamlWorkItem(
            Object arg
            )
        {
            //
            // PreSharp uses message numbers that the C# compiler doesn't know about.
            // Disable the C# complaints, per the PreSharp documentation.
            #pragma warning disable 1634, 1691
            //
            // PreSharp complains about catching NullReference (and other) exceptions.
            // This is an async model and we need to catch all exception ourselves and then
            // send them to the completion delegate
            #pragma warning disable 56500
            try
            {
                if(!_serializationOperationCanceled)
                {
                    if(_operationStack.Count > 0)
                    {
                        Object objectOnStack = _operationStack.Pop();
 
                        if(objectOnStack.GetType() ==
                           typeof(System.Windows.Xps.Serialization.SerializationManagerOperationContextStack))
                        {
                           SerializationManagerOperationContextStack context =
                                                                     (SerializationManagerOperationContextStack)objectOnStack;
 
                            context.ReachSerializer.SerializeObject(context.SerializedObject);
                        }
                        else if(typeof(System.Windows.Xps.Serialization.NGCSerializerContext).IsAssignableFrom(objectOnStack.GetType()))
                        {
                            NGCSerializerContext context = (NGCSerializerContext)objectOnStack;
                            context.Serializer.AsyncOperation(context);
                        }
                        PostSerializationTask(new DispatcherOperationCallback(InvokeSaveAsXamlWorkItem));
                    }
                    else
                    {
                        NGCSerializationCompletionMethod();
                    }
                }
            }
            catch(Exception e)
            {
                EndDocument(true);
                if(CriticalExceptions.IsCriticalException(e))
                {
                    throw;
                }
 
                //
                // Indicate that an error happened
                //
                bool canceled = false;
 
                XpsSerializationCompletedEventArgs args = new XpsSerializationCompletedEventArgs(canceled,
                                                                                                 null,
                                                                                                 e);
 
                _serializationOperationCanceled = true;
 
                PostSerializationTask(new DispatcherOperationCallback(OnNGCSerializationCompleted), args);
 
                return null;
            }
            #pragma warning restore 56500
            #pragma warning restore 1634, 1691
 
            return null;
        }
 
 
        /// <remarks>
        /// The logic in the method IsAsyncWorkPending *MUST* mirror the logic in InvokeSaveAsXamlBatchWorkItem
        /// IsAsyncWorkPending must return true when the manager is in a state that
        /// causes InvokeSaveAsXamlBatchWorkItem to process pending items.
        /// <remarks>
        internal
        Object
        InvokeSaveAsXamlBatchWorkItem(
            Object arg
            )
        {
            //
            // PreSharp uses message numbers that the C# compiler doesn't know about.
            // Disable the C# complaints, per the PreSharp documentation.
            #pragma warning disable 1634, 1691
            //
            // PreSharp complains about catching NullReference (and other) exceptions.
            // This is an async model and we need to catch all exception ourselves and then
            // send them to the completion delegate
            #pragma warning disable 56500
            try
            {
                // This logic must be mirrored in IsAsyncWorkPending see remarks.
 
                if (!_serializationOperationCanceled)
                {
                    if(!_isBatchWorkItemInProgress && _batchOperationQueue.Count > 0)
                    {
                        BatchOperationWorkItem batchOperationWorkItem = (BatchOperationWorkItem)_batchOperationQueue.Dequeue();
 
                        if(batchOperationWorkItem.OperationType == BatchOperationType.batchWrite)
                        {
                            StartPage();
 
                            ReachSerializer reachSerializer = GetSerializer(batchOperationWorkItem.SerializedObject);
 
                            if(reachSerializer != null)
                            {
                                //
                                // Prepare the context that is going to be pushed on the stack
                                //
                                SerializationManagerOperationContextStack
                                contextStack = new SerializationManagerOperationContextStack(reachSerializer,
                                                                                             batchOperationWorkItem.SerializedObject);
                                //
                                // At this stage, start calling another method which would peak at the stack
                                //
                                _operationStack.Push(contextStack);
 
                                PostSerializationTask(new DispatcherOperationCallback(InvokeSaveAsXamlBatchWorkItem));
                            }
                            else
                            {
                                throw new XpsSerializationException(SR.ReachSerialization_NoSerializer);
                            }
                            _isBatchWorkItemInProgress = true;
                        }
                        else if(batchOperationWorkItem.OperationType == BatchOperationType.batchCommit)
                        {
                            if (_isSimulating)
                            {
                                EndDocument();
                            }
                            NGCSerializationCompletionMethod();
                        }
                    }
                    else
                    {
                        if(_operationStack.Count > 0)
                        {
                            Object objectOnStack = _operationStack.Pop();
 
                            if(objectOnStack.GetType() ==
                               typeof(System.Windows.Xps.Serialization.SerializationManagerOperationContextStack))
                            {
                               SerializationManagerOperationContextStack context =
                                                                         (SerializationManagerOperationContextStack)objectOnStack;
 
                                context.ReachSerializer.SerializeObject(context.SerializedObject);
                            }
                            else if(typeof(System.Windows.Xps.Serialization.NGCSerializerContext).IsAssignableFrom(objectOnStack.GetType()))
                            {
                                NGCSerializerContext context = (NGCSerializerContext)objectOnStack;
                                context.Serializer.AsyncOperation(context);
                            }
                            PostSerializationTask(new DispatcherOperationCallback(InvokeSaveAsXamlBatchWorkItem));
                        }
                        else
                        {
                            EndPage();
                            _isBatchWorkItemInProgress = false;
                        }
                    }
                }
            }
            catch(Exception e)
            {
                //
                //  Force document count back to 1
                //  This causes EndDocument to effectivly abort dispite not properly calling an End
                //  document for each Start Document
                //
                // 07/24/06 brianad
                //
                EndDocument(true);
                if (CriticalExceptions.IsCriticalException(e))
                {
                    throw;
                }
 
                //
                // Indicate that an error happened
                //
                bool canceled = false;
 
                XpsSerializationCompletedEventArgs args = new XpsSerializationCompletedEventArgs(canceled,
                                                                                                 null,
                                                                                                 e);
 
                _serializationOperationCanceled = true;
 
                PostSerializationTask(new DispatcherOperationCallback(OnNGCSerializationCompleted), args);
 
                return null;
            }
            #pragma warning restore 56500
            #pragma warning restore 1634, 1691
 
            return null;
        }
 
        /// <summary>
        ///
        /// </summary>
        public
        void
        CancelAsync(
            )
        {
            bool canceled = true;
 
            XpsSerializationCompletedEventArgs e = new XpsSerializationCompletedEventArgs(canceled,
                                                                                          null,
                                                                                          null);
 
            _serializationOperationCanceled = true;
 
            if(_startDocCnt != 0)
            {
                _device.AbortDocument();
                _startDocCnt = 0;
            }
 
            PostSerializationTask(new DispatcherOperationCallback(OnNGCSerializationCompleted), e);
        }
 
        /// <summary>
        ///
        /// </summary>
        public
        void
        Commit(
            )
        {
            if(_isBatchMode && _isSimulating)
            {
                // Wait for pending items to complete synchronously
                // otherwise the caller may dispose the underlying resource
                // before our async operations can commit remaining data
                WaitForPendingAsyncItems();
 
                // Post a final commit item
                // It's important to first drain all prior items before posting this item
                // otherwise a pending item may post a new item causing undesirable interleaving
                BatchOperationWorkItem batchOperationWorkItem = new BatchOperationWorkItem(BatchOperationType.batchCommit,
                                                                                            null);
                _batchOperationQueue.Enqueue(batchOperationWorkItem);
                PostSerializationTask(new DispatcherOperationCallback(InvokeSaveAsXamlBatchWorkItem));
 
                // Wait for pending items to complete synchronously
                WaitForPendingAsyncItems();
            }
        }
 
        /// <summary>
        ///
        /// </summary>
        public
        event
        XpsSerializationCompletedEventHandler               XpsSerializationCompleted;
 
        /// <summary>
        ///
        /// </summary>
        public
        event
        XpsSerializationPrintTicketRequiredEventHandler     XpsSerializationPrintTicketRequired;
 
        /// <summary>
        ///
        /// </summary>
        public
        event
        XpsSerializationProgressChangedEventHandler         XpsSerializationProgressChanged;
 
        /// <summary>
        /// This function GetXmlNSForType and the other four XML writer functiosn (like AcquireXmlWriter)
        /// and the two stream function (like ReleaseResourceStream) should be removed from
        /// the base PackageSerializationManager class.
        /// </summary>
        internal
        override
        String
        GetXmlNSForType(
            Type    objectType
            )
        {
            return null;
        }
 
        /// <summary>
        ///
        /// </summary>
        internal
        override
        ReachSerializer
        GetSerializer(
            Object serializedObject
            )
        {
            ReachSerializer reachSerializer = null;
 
            if((reachSerializer = base.GetSerializer(serializedObject)) == null)
            {
                reachSerializer = this.SerializersCacheManager.GetSerializer(serializedObject);
            }
 
            return reachSerializer;
        }
 
        /// <summary>
        ///
        /// </summary>
        internal
        override
        Type
        GetSerializerType(
            Type objectType
            )
        {
            Type serializerType = null;
 
 
            if (typeof(System.Windows.Documents.FixedDocumentSequence).IsAssignableFrom(objectType))
            {
                serializerType = typeof(NgcDocumentSequenceSerializerAsync);
            }
            else if (typeof(System.Windows.Documents.DocumentReferenceCollection).IsAssignableFrom(objectType))
            {
                serializerType = typeof(NgcDocumentReferenceCollectionSerializerAsync);
            }
            else if (typeof(System.Windows.Documents.FixedDocument).IsAssignableFrom(objectType))
            {
                serializerType = typeof(NgcFixedDocumentSerializerAsync);
            }
            else if(typeof(System.Windows.Documents.PageContentCollection).IsAssignableFrom(objectType))
            {
                serializerType = typeof(NgcPageContentCollectionSerializerAsync);
            }
            else if(typeof(System.Windows.Documents.PageContent).IsAssignableFrom(objectType))
            {
                serializerType = typeof(NgcPageContentSerializerAsync);
            }
            else if(typeof(System.Windows.Controls.UIElementCollection).IsAssignableFrom(objectType))
            {
                serializerType = typeof(NgcUIElementCollectionSerializerAsync);
            }
            else if(typeof(System.Windows.Documents.FixedPage).IsAssignableFrom(objectType))
            {
                serializerType = typeof(NgcFixedPageSerializerAsync);
            }
            else if (typeof(System.Windows.Documents.DocumentPaginator).IsAssignableFrom(objectType))
            {
                serializerType = typeof(NgcDocumentPaginatorSerializerAsync);
            }
            else if (typeof(System.Windows.Documents.DocumentPage).IsAssignableFrom(objectType))
            {
                serializerType = typeof(NgcDocumentPageSerializerAsync);
            }
            else if (typeof(System.Windows.Media.Visual).IsAssignableFrom(objectType))
            {
                serializerType = typeof(NgcReachVisualSerializerAsync);
            }
 
            if(serializerType == null)
            {
                serializerType = base.GetSerializerType(objectType);
            }
 
            return serializerType;
        }
 
        internal
        override
        XmlWriter
        AcquireXmlWriter(
            Type    writerType
            )
        {
            return null;
        }
 
        internal
        override
        void
        ReleaseXmlWriter(
            Type    writerType
            )
        {
            return;
        }
 
        internal
        override
        XpsResourceStream
        AcquireResourceStream(
            Type    resourceType
            )
        {
            return null;
        }
 
        internal
        override
        XpsResourceStream
        AcquireResourceStream(
            Type    resourceType,
            String  resourceID
            )
        {
            return null;
        }
 
        internal
        override
        void
        ReleaseResourceStream(
            Type    resourceType
            )
        {
            return;
        }
 
        internal
        override
        void
        ReleaseResourceStream(
            Type    resourceType,
            String  resourceID
            )
        {
            return;
        }
 
        internal
        override
        void
        AddRelationshipToCurrentPage(
            Uri targetUri,
            string relationshipName
            )
        {
            return;
        }
 
 
        internal
        override
        BasePackagingPolicy
        PackagingPolicy
        {
            get
            {
                return null;
            }
        }
 
        internal
        override
        XpsResourcePolicy
        ResourcePolicy
        {
            get
            {
                return null;
            }
        }
        #endregion PackageSerializationManager override
 
        #region Internal Properties
 
        /// <summary>
        ///
        /// </summary>
        internal
        PrintQueue
        PrintQueue
        {
            get
            {
                return _printQueue;
            }
        }
 
 
        internal
        String
        JobName
        {
            set
            {
                if (_jobName == null)
                {
                    _jobName = value;
                }
            }
 
            get
            {
                return _jobName;
            }
        }
 
        internal
        Size
        PageSize
        {
            set
            {
                _pageSize = value;
            }
 
            get
            {
                return _pageSize;
            }
        }
 
        #endregion Internal Properties
 
        #region Internal Methods
 
        /// <summary>
        ///
        /// </summary>
        ///
        internal
        void
        StartDocument(
            Object o,
            bool   documentPrintTicketRequired
            )
        {
            if(documentPrintTicketRequired)
            {
                XpsSerializationPrintTicketRequiredEventArgs e =
                new XpsSerializationPrintTicketRequiredEventArgs(PrintTicketLevel.FixedDocumentPrintTicket,
                                                                 0);
                OnNGCSerializationPrintTicketRequired(e);
            }
 
            if( _startDocCnt == 0 )
            {
 
                JobName = PrintQueue.CurrentJobSettings.Description;
 
                if(JobName == null)
                {
                    JobName = NgcSerializerUtil.InferJobName(o);
                }
 
                _device  = new MetroToGdiConverter(PrintQueue);
 
                _device.StartDocument(_jobName, _printTicketManager.ConsumeActivePrintTicket(true));
            }
            _startDocCnt++;
        }
 
        /// <summary>
        ///
        /// </summary>
        ///
        internal
        void
        EndDocument()
        {
            EndDocument(false);
        }
 
        /// <summary>
        ///
        /// </summary>
        ///
        internal
        void
        EndDocument(bool abort)
        {
            if( _startDocCnt == 1 || abort )
            {
                _device.EndDocument(abort);
 
                //
                // Inform the listener that the document has been printed
                //
                XpsSerializationProgressChangedEventArgs e =
                new XpsSerializationProgressChangedEventArgs(XpsWritingProgressChangeLevel.FixedDocumentWritingProgress,
                                                             0,
                                                             0,
                                                             null);
                OnNGCSerializationProgressChanged(e);
            }
            _startDocCnt--;
        }
 
        /// <summary>
        ///
        /// </summary>
        ///
        internal
        bool
        StartPage()
        {
            bool    bManulStartDoc = false;
 
            if (_startDocCnt == 0)
            {
                StartDocument(null,true);
                bManulStartDoc = true;
            }
 
            if (_isPrintTicketMerged == false)
            {
                XpsSerializationPrintTicketRequiredEventArgs e =
                new XpsSerializationPrintTicketRequiredEventArgs(PrintTicketLevel.FixedPagePrintTicket,
                                                                 0);
                OnNGCSerializationPrintTicketRequired(e);
            }
 
            _device.StartPage(_printTicketManager.ConsumeActivePrintTicket(true));
            _isStartPage = true;
 
            return bManulStartDoc;
        }
 
        /// <summary>
        ///
        /// </summary>
        ///
        internal
        void
        EndPage()
        {
            _device.FlushPage();
            _isStartPage = false;
            _isPrintTicketMerged = false;
 
            //
            // Inform the listener that the page has been printed
            //
            XpsSerializationProgressChangedEventArgs e =
            new XpsSerializationProgressChangedEventArgs(XpsWritingProgressChangeLevel.FixedPageWritingProgress,
                                                         0,
                                                         0,
                                                         null);
            OnNGCSerializationProgressChanged(e);
        }
 
        internal
        void
        OnNGCSerializationPrintTicketRequired(
            object operationState
            )
        {
            XpsSerializationPrintTicketRequiredEventArgs e = operationState as XpsSerializationPrintTicketRequiredEventArgs;
 
            if(XpsSerializationPrintTicketRequired != null)
            {
                e.Modified = true;
 
                if (e.PrintTicketLevel == PrintTicketLevel.FixedPagePrintTicket)
                {
                    _isPrintTicketMerged = true;
                }
 
                XpsSerializationPrintTicketRequired(this,e);
 
                _printTicketManager.ConstructPrintTicketTree(e);
            }
        }
 
        internal
        void
        OnNGCSerializationProgressChanged(
            object operationState
            )
        {
            XpsSerializationProgressChangedEventArgs e = operationState as XpsSerializationProgressChangedEventArgs;
 
            if(XpsSerializationProgressChanged != null)
            {
                XpsSerializationProgressChanged(this,e);
            }
        }
 
        /// <summary>
        ///
        /// </summary>
        ///
        internal
        void
        WalkVisual(
            Visual visual
            )
        {
            bool    bManulStartDoc = false;
            bool    bManulStartpage = false;
 
            if (_startDocCnt == 0)
            {
                StartDocument(visual,true);
                bManulStartDoc = true;
            }
            if (!_isStartPage)
            {
                StartPage();
                bManulStartpage = true;
            }
 
            //
            // Call VisualTreeFlattener to flatten the visual on IMetroDrawingContext
            //
            VisualTreeFlattener.Walk(visual, _device, PageSize, new TreeWalkProgress());
 
            if (bManulStartpage)
            {
                EndPage();
            }
            if (bManulStartDoc)
            {
                EndDocument();
            }
        }
 
        internal
        PrintTicket
        GetActivePrintTicket()
        {
            return _printTicketManager.ActivePrintTicket;
        }
 
        internal
        bool
        IsPrintTicketEventHandlerEnabled
        {
            get
            {
                if(XpsSerializationPrintTicketRequired!=null)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
 
        internal
        Stack
        OperationStack
        {
            get
            {
                return _operationStack;
            }
        }
 
        private
        void
        PostSerializationTask(
            DispatcherOperationCallback taskItem
            )
        {
            _dispatcher.BeginInvoke(DispatcherPriority.Background,
                                    taskItem,
                                    null);
        }
 
        private
        void
        PostSerializationTask(
            DispatcherOperationCallback taskItem,
            object arg
            )
        {
            _dispatcher.BeginInvoke(DispatcherPriority.Background,
                                    taskItem,
                                    arg);
        }
 
 
 
        private
        bool
        IsSerializedObjectTypeSupported(
            Object  serializedObject
            )
        {
            bool isSupported = false;
 
            Type serializedObjectType = serializedObject.GetType();
 
            if(_isBatchMode)
            {
                if((typeof(System.Windows.Media.Visual).IsAssignableFrom(serializedObjectType)) &&
                    (serializedObjectType != typeof(System.Windows.Documents.FixedPage)))
                {
                    isSupported = true;
                }
            }
            else
            {
                if ( (serializedObjectType == typeof(System.Windows.Documents.FixedDocumentSequence)) ||
                     (serializedObjectType == typeof(System.Windows.Documents.FixedDocument))    ||
                     (serializedObjectType == typeof(System.Windows.Documents.FixedPage))        ||
                     (typeof(System.Windows.Documents.DocumentPaginator).IsAssignableFrom(serializedObjectType)) ||
                     (typeof(System.Windows.Media.Visual).IsAssignableFrom(serializedObjectType)) )
                {
                    isSupported = true;
                }
            }
            return isSupported;
        }
 
        private
        void
        NGCSerializationCompletionMethod(
            )
        {
            bool canceled = false;
 
            XpsSerializationCompletedEventArgs e = new XpsSerializationCompletedEventArgs(canceled,
                                                                                          null,
                                                                                          null);
 
            PostSerializationTask(new DispatcherOperationCallback(OnNGCSerializationCompleted), e);
        }
 
        private
        object
        OnNGCSerializationCompleted(
            object operationState
            )
        {
            XpsSerializationCompletedEventArgs e = operationState as XpsSerializationCompletedEventArgs;
 
            if (XpsSerializationCompleted != null)
            {
                XpsSerializationCompleted(this, e);
            }
            return null;
        }
 
        private
        bool
        IsDocumentSequencePrintTicketRequired(
            Object  serializedObject
            )
        {
            bool isRequired = false;
 
            Type serializedObjectType = serializedObject.GetType();
 
            if ((serializedObjectType == typeof(System.Windows.Documents.FixedDocument))    ||
                (serializedObjectType == typeof(System.Windows.Documents.FixedPage))        ||
                (typeof(System.Windows.Documents.DocumentPaginator).IsAssignableFrom(serializedObjectType)) ||
                (typeof(System.Windows.Media.Visual).IsAssignableFrom(serializedObjectType)) )
            {
                isRequired = true;
            }
 
            return isRequired;
        }
 
        private
        void
        WaitForPendingAsyncItems(
            )
        {
            do
            {
                _dispatcher.Invoke(DispatcherPriority.Background, (DispatcherOperationCallback)(_ => null), null);
            }
            while (IsAsyncWorkPending());
        }
 
        /// <remarks>
        /// The logic in the method IsAsyncWorkPending *MUST* mirror the logic in InvokeSaveAsXamlBatchWorkItem
        /// IsAsyncWorkPending must return true when the manager is in a state that
        /// causes InvokeSaveAsXamlBatchWorkItem to process pending items.
        /// <remarks>
        private
        bool
        IsAsyncWorkPending(
            )
        {
            // This logic must mirror InvokeSaveAsXamlBatchWorkItem see remarks.
 
            if(!_serializationOperationCanceled)
            {
                if(!_isBatchWorkItemInProgress && _batchOperationQueue.Count > 0)
                {
                    // InvokeSaveAsXamlBatchWorkItem is expected to process an item from _batchOperationQueue
                    return true;
                }
                else {
                    if (_operationStack.Count > 0)
                    {
                        // InvokeSaveAsXamlBatchWorkItem is expected to process an item from _operationStack
                        return true;
                    }
                }
            }
 
            return false;
        }
 
        #endregion Internal Methods
 
        #region Private Member
 
        private     Dispatcher              _dispatcher;
        private     PrintQueue              _printQueue;
        private     int                     _startDocCnt;
        private     bool                    _isStartPage;
        private     MetroToGdiConverter     _device;
        private     String                  _jobName;
        private     Stack                   _operationStack;
        private     bool                    _isBatchMode;
        private     Queue                   _batchOperationQueue;
        private     bool                    _serializationOperationCanceled;
        private     bool                    _isSimulating;
        private     bool                    _isBatchWorkItemInProgress;
        private     NgcPrintTicketManager   _printTicketManager;
        private     bool                    _isPrintTicketMerged;
        private     Size                    _pageSize;
 
        #endregion Private Member
    };
}