|
// 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.
#nullable disable
using System.Diagnostics;
using MS.Internal.Xaml.Context;
namespace System.Xaml
{
internal enum DeferringMode
{
Off,
TemplateStarting,
TemplateDeferring,
TemplateReady,
}
internal class DeferringWriter : XamlWriter, IXamlLineInfoConsumer
{
DeferringMode _mode;
bool _handled;
ObjectWriterContext _context;
XamlNodeList _deferredList;
XamlWriter _deferredWriter;
IXamlLineInfoConsumer _deferredLineInfoConsumer;
int _deferredTreeDepth;
public DeferringWriter(ObjectWriterContext context)
{
_context = context;
_mode = DeferringMode.Off;
}
public void Clear()
{
_handled = false;
_mode = DeferringMode.Off;
_deferredList = null;
_deferredTreeDepth = -1;
}
public bool Handled
{
get { return _handled; }
}
public DeferringMode Mode
{
get { return _mode; }
}
public XamlNodeList CollectTemplateList()
{
XamlNodeList retValue = _deferredList;
_deferredList = null;
_mode = DeferringMode.Off;
return retValue;
}
#region XamlWriter Members
public override void WriteGetObject()
{
WriteObject(null, true, "WriteGetObject");
}
public override void WriteStartObject(XamlType xamlType)
{
WriteObject(xamlType, false, "WriteStartObject");
}
void WriteObject(XamlType xamlType, bool fromMember, string methodName)
{
_handled = false;
switch (_mode)
{
case DeferringMode.Off:
break;
case DeferringMode.TemplateReady:
throw new XamlInternalException(SR.Format(SR.TemplateNotCollected, methodName));
case DeferringMode.TemplateStarting:
StartDeferredList();
_mode = DeferringMode.TemplateDeferring;
goto case DeferringMode.TemplateDeferring;
case DeferringMode.TemplateDeferring:
if (fromMember)
{
_deferredWriter.WriteGetObject();
}
else
{
_deferredWriter.WriteStartObject(xamlType);
}
_deferredTreeDepth += 1;
_handled = true;
break;
default:
throw new XamlInternalException(SR.Format(SR.MissingCase, _mode.ToString(), methodName));
}
}
public override void WriteEndObject()
{
_handled = false;
switch (_mode)
{
case DeferringMode.Off:
break;
case DeferringMode.TemplateReady:
throw new XamlInternalException(SR.Format(SR.TemplateNotCollected, "WriteEndObject"));
case DeferringMode.TemplateDeferring:
_deferredWriter.WriteEndObject();
_handled = true;
_deferredTreeDepth -= 1;
if (_deferredTreeDepth == 0)
{
_deferredWriter.Close();
_deferredWriter = null;
_mode = DeferringMode.TemplateReady;
}
break;
default:
throw new XamlInternalException(SR.Format(SR.MissingCase, _mode.ToString(), "WriteEndObject"));
}
}
public override void WriteStartMember(XamlMember property)
{
_handled = false;
switch (_mode)
{
case DeferringMode.Off:
if (property.DeferringLoader != null)
{
_mode = DeferringMode.TemplateStarting;
// We assume in WriteValue that this property can never be multi-valued
Debug.Assert(!property.IsDirective && !property.IsUnknown);
}
break;
case DeferringMode.TemplateReady:
throw new XamlInternalException(SR.Format(SR.TemplateNotCollected, "WriteMember"));
case DeferringMode.TemplateDeferring:
_deferredWriter.WriteStartMember(property);
_handled = true;
break;
default:
throw new XamlInternalException(SR.Format(SR.MissingCase, _mode.ToString(), "WriteMember"));
}
}
public override void WriteEndMember()
{
_handled = false;
switch (_mode)
{
case DeferringMode.Off:
break;
case DeferringMode.TemplateReady:
throw new XamlInternalException(SR.Format(SR.TemplateNotCollected, "WriteEndMember"));
case DeferringMode.TemplateDeferring:
_deferredWriter.WriteEndMember();
_handled = true;
break;
default:
throw new XamlInternalException(SR.Format(SR.MissingCase, _mode.ToString(), "WriteEndMember"));
}
}
public override void WriteValue(object value)
{
_handled = false;
switch (_mode)
{
case DeferringMode.Off:
break;
case DeferringMode.TemplateReady:
throw new XamlInternalException(SR.Format(SR.TemplateNotCollected, "WriteValue"));
case DeferringMode.TemplateStarting:
// This handles the case of SM template; V object; EM
Debug.Assert(_deferredTreeDepth == 0);
if (value is XamlNodeList)
{
_deferredList = (XamlNodeList)value;
_mode = DeferringMode.TemplateReady;
_handled = true;
}
else
{
StartDeferredList();
_mode = DeferringMode.TemplateDeferring;
goto case DeferringMode.TemplateDeferring;
}
break;
case DeferringMode.TemplateDeferring:
_deferredWriter.WriteValue(value);
_handled = true;
break;
default:
throw new XamlInternalException(SR.Format(SR.MissingCase, _mode.ToString(), "WriteValue"));
}
}
public override void WriteNamespace(NamespaceDeclaration namespaceDeclaration)
{
switch (_mode)
{
case DeferringMode.Off:
return;
case DeferringMode.TemplateReady:
throw new XamlInternalException(SR.Format(SR.TemplateNotCollected, "WriteNamespace"));
case DeferringMode.TemplateStarting:
StartDeferredList();
_mode = DeferringMode.TemplateDeferring;
goto case DeferringMode.TemplateDeferring;
case DeferringMode.TemplateDeferring:
_deferredWriter.WriteNamespace(namespaceDeclaration);
_handled = true;
break;
default:
throw new XamlInternalException(SR.Format(SR.MissingCase, _mode.ToString(), "WriteNamespace"));
}
}
protected override void Dispose(bool disposing)
{
try
{
if (disposing && !IsDisposed)
{
if (_deferredWriter != null)
{
_deferredWriter.Close();
_deferredWriter = null;
_deferredLineInfoConsumer = null;
}
}
}
finally
{
base.Dispose(disposing);
}
}
public override XamlSchemaContext SchemaContext
{
get { return _context.SchemaContext; }
}
#endregion
#region IXamlLineInfoConsumer Members
public void SetLineInfo(int lineNumber, int linePosition)
{
switch (_mode)
{
case DeferringMode.Off:
return;
case DeferringMode.TemplateReady:
throw new XamlInternalException(SR.Format(SR.TemplateNotCollected, nameof(SetLineInfo)));
case DeferringMode.TemplateStarting:
StartDeferredList();
// do not change _mode here - only the XamlWriter members should do that
goto case DeferringMode.TemplateDeferring;
case DeferringMode.TemplateDeferring:
if (_deferredLineInfoConsumer != null)
{
_deferredLineInfoConsumer.SetLineInfo(lineNumber, linePosition);
}
break;
default:
throw new XamlInternalException(SR.Format(SR.MissingCase, _mode.ToString(), nameof(SetLineInfo)));
}
}
public bool ShouldProvideLineInfo
{
get { return true; }
}
#endregion
private void StartDeferredList()
{
// the list may have been created already by SetLineInfo
if (_deferredList == null)
{
_deferredList = new XamlNodeList(_context.SchemaContext);
_deferredWriter = _deferredList.Writer;
_deferredLineInfoConsumer = _deferredWriter as IXamlLineInfoConsumer;
_deferredTreeDepth = 0;
}
}
}
}
|