e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
86 lines
3.4 KiB
C#
86 lines
3.4 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.Activities.XamlIntegration
|
|
{
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Windows.Markup;
|
|
using System.Xaml;
|
|
|
|
public class SerializableFuncDeferringLoader : XamlDeferringLoader
|
|
{
|
|
const string xmlPrefix = "xml";
|
|
|
|
public override object Load(XamlReader xamlReader, IServiceProvider context)
|
|
{
|
|
FuncFactory factory = FuncFactory.CreateFactory(xamlReader, context);
|
|
IXamlNamespaceResolver nsResolver = context.GetService(typeof(IXamlNamespaceResolver)) as IXamlNamespaceResolver;
|
|
if (nsResolver != null)
|
|
{
|
|
factory.ParentNamespaces = nsResolver.GetNamespacePrefixes().ToList();
|
|
}
|
|
return factory.GetFunc();
|
|
}
|
|
|
|
public override XamlReader Save(object value, IServiceProvider serviceProvider)
|
|
{
|
|
FuncFactory factory = GetFactory(value as Delegate);
|
|
if (factory == null)
|
|
{
|
|
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.SavingFuncToXamlNotSupported));
|
|
}
|
|
XamlReader result = factory.Nodes.GetReader();
|
|
if (factory.ParentNamespaces != null)
|
|
{
|
|
result = InsertNamespaces(result, factory.ParentNamespaces);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static FuncFactory GetFactory(Delegate func)
|
|
{
|
|
return (func != null) ? func.Target as FuncFactory : null;
|
|
}
|
|
|
|
// We don't know what namespaces are actually used inside convertible values, so any namespaces
|
|
// that were in the parent scope on load need to be regurgitated on save, unless the prefixes were
|
|
// shadowed in the child scope.
|
|
// This can potentially cause namespace bloat, but the alternative is emitting unloadable XAML.
|
|
static XamlReader InsertNamespaces(XamlReader reader, IEnumerable<NamespaceDeclaration> parentNamespaces)
|
|
{
|
|
XamlNodeQueue namespaceNodes = new XamlNodeQueue(reader.SchemaContext);
|
|
HashSet<string> childPrefixes = new HashSet<string>();
|
|
while (reader.Read() && reader.NodeType == XamlNodeType.NamespaceDeclaration)
|
|
{
|
|
childPrefixes.Add(reader.Namespace.Prefix);
|
|
namespaceNodes.Writer.WriteNode(reader);
|
|
}
|
|
foreach (NamespaceDeclaration parentNamespace in parentNamespaces)
|
|
{
|
|
if (!childPrefixes.Contains(parentNamespace.Prefix) &&
|
|
!IsXmlNamespace(parentNamespace))
|
|
{
|
|
namespaceNodes.Writer.WriteNamespace(parentNamespace);
|
|
}
|
|
}
|
|
if (!reader.IsEof)
|
|
{
|
|
namespaceNodes.Writer.WriteNode(reader);
|
|
}
|
|
return new ConcatenatingXamlReader(namespaceNodes.Reader, reader);
|
|
}
|
|
|
|
// We need to special-case the XML namespace because it is always in scope,
|
|
// but can't actually be written to XML.
|
|
static bool IsXmlNamespace(NamespaceDeclaration namespaceDecl)
|
|
{
|
|
return namespaceDecl.Prefix == xmlPrefix && namespaceDecl.Namespace == XamlLanguage.Xml1998Namespace;
|
|
}
|
|
}
|
|
}
|
|
|
|
|