| File: Serialization\Manager\XpsOMSerializationManagerAsync.cs | Web Access |
| Project: src\wpf\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. using System.Collections; using System.Xml; using System.Windows.Xps.Packaging; using System.Windows.Threading; using MS.Internal; namespace System.Windows.Xps.Serialization { internal class XpsOMSerializationManagerAsync : XpsOMSerializationManager, IXpsSerializationManagerAsync { #region Constructor public XpsOMSerializationManagerAsync( XpsOMPackagingPolicy packagingPolicy, bool batchMode ): base(packagingPolicy, batchMode) { _dispatcher = Dispatcher.CurrentDispatcher; _serializationOperationCanceled = false; _currentPageXmlWriter = null; _isBatchWorkItemInProgress = false; _operationStack = new Stack(); _batchOperationQueue = new Queue(); } #endregion Constructor #region packageSerializationManager override public override void SaveAsXaml( Object serializedObject ) { ArgumentNullException.ThrowIfNull(serializedObject); if (!XpsSerializationManager.IsSerializedObjectTypeSupported(serializedObject, IsBatchMode)) { throw new XpsSerializationException(SR.ReachSerialization_NotSupported); } if (Simulator == null) { Simulator = new XpsOMHierarchySimulator(this, serializedObject); } if (!IsSimulating) { Simulator.BeginConfirmToXPSStructure(IsBatchMode); IsSimulating = true; } 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); } } } #endregion packageSerializationManager override #region internal methods internal Object InvokeSaveAsXamlWorkItem( Object arg ) { 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.ReachSerializerContext).IsAssignableFrom(objectOnStack.GetType())) { ReachSerializerContext context = (ReachSerializerContext)objectOnStack; context.Serializer.AsyncOperation(context); } PostSerializationTask(new DispatcherOperationCallback(InvokeSaveAsXamlWorkItem)); } else { Simulator.EndConfirmToXPSStructure(IsBatchMode); XPSSerializationCompletionMethod(); } } } catch (Exception e) when (!CriticalExceptions.IsCriticalException(e)) { // // Indicate that an error happened // bool canceled = false; XpsSerializationCompletedEventArgs args = new XpsSerializationCompletedEventArgs(canceled, null, e); _serializationOperationCanceled = true; PostSerializationTask(new DispatcherOperationCallback(OnXPSSerializationCompleted), args); } return null; } internal Object InvokeSaveAsXamlBatchWorkItem( Object arg ) { 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) { _currentPageXmlWriter = Simulator.SimulateBeginFixedPage(); 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) { Simulator.EndConfirmToXPSStructure(IsBatchMode); XPSSerializationCompletionMethod(); } } 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.ReachSerializerContext).IsAssignableFrom(objectOnStack.GetType())) { ReachSerializerContext context = (ReachSerializerContext)objectOnStack; context.Serializer.AsyncOperation(context); } PostSerializationTask(new DispatcherOperationCallback(InvokeSaveAsXamlBatchWorkItem)); } else { Simulator.SimulateEndFixedPage(_currentPageXmlWriter); _isBatchWorkItemInProgress = false; _currentPageXmlWriter = null; } } } } catch (Exception e) when (!CriticalExceptions.IsCriticalException(e)) { XpsSerializationCompletedEventArgs args = new XpsSerializationCompletedEventArgs(false, // Indicate that an error happened null, e); _serializationOperationCanceled = true; PostSerializationTask(new DispatcherOperationCallback(OnXPSSerializationCompleted), args); } return null; } public void CancelAsync( ) { XpsSerializationCompletedEventArgs e = new XpsSerializationCompletedEventArgs(true, null, null); _serializationOperationCanceled = true; PostSerializationTask(new DispatcherOperationCallback(OnXPSSerializationCompleted), e); } internal override 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(); } } internal override Type GetSerializerType( Type objectType ) { Type serializerType = null; if (typeof(System.Windows.Documents.FixedDocument).IsAssignableFrom(objectType)) { serializerType = typeof(XpsOMFixedDocumentSerializerAsync); } else if (typeof(System.Windows.Documents.PageContentCollection).IsAssignableFrom(objectType)) { serializerType = typeof(ReachPageContentCollectionSerializerAsync); } else if (typeof(System.Windows.Documents.PageContent).IsAssignableFrom(objectType)) { serializerType = typeof(ReachPageContentSerializerAsync); } else if (typeof(System.Windows.Controls.UIElementCollection).IsAssignableFrom(objectType)) { serializerType = typeof(ReachUIElementCollectionSerializerAsync); } else if (typeof(System.Windows.Documents.FixedPage).IsAssignableFrom(objectType)) { serializerType = typeof(XpsOMFixedPageSerializerAsync); } else if (typeof(System.Windows.Documents.FixedDocumentSequence).IsAssignableFrom(objectType)) { serializerType = typeof(XpsOMDocumentSequenceSerializerAsync); } else if (typeof(System.Windows.Documents.DocumentReferenceCollection).IsAssignableFrom(objectType)) { serializerType = typeof(ReachDocumentReferenceCollectionSerializerAsync); } else if (typeof(System.Windows.Documents.DocumentReference).IsAssignableFrom(objectType)) { serializerType = typeof(ReachDocumentReferenceSerializerAsync); } else if (typeof(System.Windows.Documents.DocumentPaginator).IsAssignableFrom(objectType)) { serializerType = typeof(XpsOMDocumentPaginatorSerializerAsync); } else if (typeof(System.Windows.Documents.DocumentPage).IsAssignableFrom(objectType)) { serializerType = typeof(XpsOMDocumentPageSerializerAsync); } else if (typeof(System.Windows.Media.Visual).IsAssignableFrom(objectType)) { serializerType = typeof(ReachVisualSerializerAsync); } else if (typeof(System.Printing.PrintTicket).IsAssignableFrom(objectType)) { serializerType = typeof(PrintTicketSerializer); } if (serializerType == null) { base.GetSerializerType(objectType); } return serializerType; } internal Stack OperationStack { get { return _operationStack; } } Stack IXpsSerializationManagerAsync.OperationStack { get { return OperationStack; } } #endregion internal methods #region private methods 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 void XPSSerializationCompletionMethod( ) { bool canceled = false; XpsSerializationCompletedEventArgs e = new XpsSerializationCompletedEventArgs(canceled, null, null); PostSerializationTask(new DispatcherOperationCallback(OnXPSSerializationCompleted), e); } private object OnXPSSerializationCompleted( object operationState ) { XpsSerializationCompletedEventArgs e = operationState as XpsSerializationCompletedEventArgs; if (XpsSerializationCompleted != null) { XpsSerializationCompleted(this, e); } return null; } 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 private methods #region events public event XpsSerializationCompletedEventHandler XpsSerializationCompleted; #endregion events #region private data private Dispatcher _dispatcher; private bool _serializationOperationCanceled; private XmlWriter _currentPageXmlWriter; private bool _isBatchWorkItemInProgress; private Stack _operationStack; private Queue _batchOperationQueue; #endregion private data } }