1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
|
//-----------------------------------------------------------------------------
// 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;
}
}
}
|