|
// 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.Xaml;
using MS.Internal.Xaml.Runtime;
using XAML3 = System.Windows.Markup;
namespace MS.Internal.Xaml.Context
{
internal enum FixupType
{
MarkupExtensionFirstRun, // An ME that can't be run because it has pending fixups on its properties
MarkupExtensionRerun, // An ME that was run and returned a FixupToken
PropertyValue, // A TC on a property that returned a FixupToken
ObjectInitializationValue, // A TC on an object that returned a FixupToken
UnresolvedChildren, // An object that can't be EndInited because it has pending fixups on its properties
};
internal class FixupTargetKeyHolder
{
public FixupTargetKeyHolder(object key)
{
Key = key;
}
public object Key { get; set; }
}
internal class FixupTarget : IAddLineInfo
{
/// <summary>
/// The Property the value will be assigned into.
/// In the case of FixupType.Property, this property will be set directly
/// when the Name is known.
/// </summary>
public XamlMember Property { get; set; }
/// <summary>
/// The Instance the Property is on.
/// </summary>
public object Instance { get; set; }
/// <summary>
/// The x:Name, if any, of Instance. May not be set yet if InstanceIsOnTheStack is still true.
/// </summary>
public string InstanceName { get; set; }
/// <summary>
/// The XamlType of the Instance (taken from the Frame, not exactly the type of the instance)
/// </summary>
public XamlType InstanceType { get; set; }
/// <summary>
/// If Property is XamlLanguage.Items, then all the items being added to the target collection
/// are stored in a temporary holding collection. This is the index of the location in the collection
/// where this token is stored.
/// </summary>
public int TemporaryCollectionIndex { get; set; }
/// <summary>
/// The LineNumber to use when calling EndInit on the Target Instance
/// </summary>
public int EndInstanceLineNumber { get; set; }
/// <summary>
/// The LinePosition to use when calling EndInit on the Target Instance
/// </summary>
public int EndInstanceLinePosition { get; set; }
/// <summary>
/// The ObjectWriterFrame and the FixupTarget need to both be updated when the Key is changed.
/// We create a KeyHolder to accomplish this
/// </summary>
public FixupTargetKeyHolder KeyHolder { get; set; }
/// <summary>
/// Whether Instance is still on the live builder stack. We will use this to determine
/// whether to call EndInit on it when all fixups are resolved.
/// </summary>
public bool InstanceIsOnTheStack { get; set; }
/// <summary>
/// Whether Instance was retrieved from a property (i.e. was a GO). If so, we don't call EndInit on it.
/// </summary>
public bool InstanceWasGotten { get; set; }
XamlException IAddLineInfo.WithLineInfo(XamlException ex)
{
if (EndInstanceLineNumber > 0)
{
ex.SetLineInfo(EndInstanceLineNumber, EndInstanceLinePosition);
}
return ex;
}
}
internal class NameFixupToken : IAddLineInfo
{
List<string> _names;
List<XAML3.INameScopeDictionary> _nameScopeDictionaryList;
public NameFixupToken()
{
_names = new List<string>();
_nameScopeDictionaryList = new List<XAML3.INameScopeDictionary>();
Target = new FixupTarget();
Target.TemporaryCollectionIndex = -1;
Target.InstanceIsOnTheStack = true;
}
public bool CanAssignDirectly { get; set; }
public FixupType FixupType { get; set; }
public int LineNumber { get; set; }
public int LinePosition { get; set; }
public FixupTarget Target { get; set; }
private XamlRuntime _runtime;
public XamlRuntime Runtime
{
get { return _runtime; }
set
{
Debug.Assert(_runtime is null);
_runtime = value;
}
}
private ObjectWriterContext _targetContext;
public ObjectWriterContext TargetContext
{
get
{
if (_targetContext is null)
{
_targetContext = new ObjectWriterContext(SavedContext, null, null, Runtime);
}
return _targetContext;
}
}
/// <summary>
/// Saved state for the reparse option.
/// </summary>
public XamlSavedContext SavedContext { get; set; }
/// <summary>
/// Saved List of Name Scopes. With simple fixups we don't have a full context stack.
/// </summary>
public List<XAML3.INameScopeDictionary> NameScopeDictionaryList
{
get { return _nameScopeDictionaryList; }
}
public List<String> NeededNames
{
get { return _names; }
}
// For simple fixups (CanAssignDirectly), this property is the referenced object when the
// name is finally resolved.
// For UnresolvedChildren fixups, this is the object that has
// unresolved children (which is in turn blocking its parent, Target.Instance, from being
// fully initialized).
// For other fixup types, this property is null.
public object ReferencedObject { get; set; }
internal object ResolveName(string name)
{
object namedObject = null;
if (CanAssignDirectly)
{
foreach (XAML3.INameScopeDictionary nameScope in NameScopeDictionaryList)
{
namedObject = nameScope.FindName(name);
if (namedObject is not null)
{
break;
}
}
}
else
{
TargetContext.IsInitializedCallback = null;
namedObject = TargetContext.ResolveName(name, out _);
}
return namedObject;
}
XamlException IAddLineInfo.WithLineInfo(XamlException ex)
{
if (LineNumber > 0)
{
ex.SetLineInfo(LineNumber, LinePosition);
}
return ex;
}
}
}
|