[12762] | 1 | using System;
|
---|
| 2 | using System.IO;
|
---|
| 3 | using System.Xml;
|
---|
| 4 | using System.Linq;
|
---|
| 5 | using System.Text;
|
---|
| 6 | using System.Reflection;
|
---|
| 7 | using System.Collections;
|
---|
| 8 | using System.Globalization;
|
---|
| 9 | using System.Collections.Generic;
|
---|
| 10 |
|
---|
| 11 | using System.Windows;
|
---|
| 12 | using System.Windows.Markup;
|
---|
| 13 | using System.Windows.Markup.Primitives;
|
---|
| 14 |
|
---|
| 15 | using SharpVectors.Runtime;
|
---|
| 16 | using SharpVectors.Renderers;
|
---|
| 17 | using SharpVectors.Renderers.Wpf;
|
---|
| 18 | using SharpVectors.Renderers.Utils;
|
---|
| 19 |
|
---|
| 20 | namespace SharpVectors.Converters
|
---|
| 21 | {
|
---|
| 22 | /// <summary>
|
---|
| 23 | /// This is a customized XAML writer, which provides Extensible Application
|
---|
| 24 | /// Markup Language (XAML) serialization of provided runtime objects into XAML.
|
---|
| 25 | /// </summary>
|
---|
| 26 | /// <remarks>
|
---|
| 27 | /// This is designed to be used by the SVG to XAML converters, and may not be
|
---|
| 28 | /// useful in general applications.
|
---|
| 29 | /// </remarks>
|
---|
| 30 | public sealed class XmlXamlWriter
|
---|
| 31 | {
|
---|
| 32 | #region Private Fields
|
---|
| 33 |
|
---|
| 34 | private bool _nullExtension;
|
---|
| 35 | private Type _nullType;
|
---|
| 36 |
|
---|
| 37 | private string _windowsDir;
|
---|
| 38 | private string _windowsPath;
|
---|
| 39 |
|
---|
| 40 | private NamespaceCache _namespaceCache;
|
---|
| 41 | private WpfDrawingSettings _wpfSettings;
|
---|
| 42 |
|
---|
| 43 | private Dictionary<Type, string> _contentProperties;
|
---|
| 44 | private Dictionary<string, NamespaceMap> _dicNamespaceMap;
|
---|
| 45 |
|
---|
| 46 | #endregion
|
---|
| 47 |
|
---|
| 48 | #region Constructors and Destructor
|
---|
| 49 |
|
---|
| 50 | /// <overloads>
|
---|
| 51 | /// Initializes a new instance of the <see cref="XmlXamlWriter"/> class.
|
---|
| 52 | /// </overloads>
|
---|
| 53 | /// <summary>
|
---|
| 54 | /// Initializes a new instance of the <see cref="XmlXamlWriter"/> class
|
---|
| 55 | /// with the default settings.
|
---|
| 56 | /// </summary>
|
---|
| 57 | public XmlXamlWriter()
|
---|
| 58 | : this(null)
|
---|
| 59 | {
|
---|
| 60 | }
|
---|
| 61 |
|
---|
| 62 | /// <summary>
|
---|
| 63 | /// Initializes a new instance of the <see cref="XmlXamlWriter"/> class
|
---|
| 64 | /// with the specified settings.
|
---|
| 65 | /// </summary>
|
---|
| 66 | /// <param name="settings">
|
---|
| 67 | /// An instance of <see cref="WpfDrawingSettings"/> specifying the
|
---|
| 68 | /// rendering options.
|
---|
| 69 | /// </param>
|
---|
| 70 | public XmlXamlWriter(WpfDrawingSettings settings)
|
---|
| 71 | {
|
---|
| 72 | _nullType = typeof(NullExtension);
|
---|
| 73 | _namespaceCache = new NamespaceCache();
|
---|
| 74 | _dicNamespaceMap = new Dictionary<string, NamespaceMap>(StringComparer.OrdinalIgnoreCase);
|
---|
| 75 | _contentProperties = new Dictionary<Type, string>();
|
---|
| 76 |
|
---|
| 77 | _windowsPath = "%WINDIR%";
|
---|
| 78 | _windowsDir = Environment.ExpandEnvironmentVariables(_windowsPath).ToLower();
|
---|
| 79 |
|
---|
| 80 | _windowsDir = _windowsDir.Replace(@"\", "/");
|
---|
| 81 | _wpfSettings = settings;
|
---|
| 82 | }
|
---|
| 83 |
|
---|
| 84 | #endregion
|
---|
| 85 |
|
---|
| 86 | #region Public Properties
|
---|
| 87 |
|
---|
| 88 | /// <summary>
|
---|
| 89 | /// Gets or sets a value indicating whether to include a null markup
|
---|
| 90 | /// extension in the output XAML.
|
---|
| 91 | /// </summary>
|
---|
| 92 | /// <value>
|
---|
| 93 | /// This is <see langword="true"/> if the null markup extension is
|
---|
| 94 | /// included in the output XAML; otherwise, it is <see langword="false"/>.
|
---|
| 95 | /// The default is <see langword="false"/>.
|
---|
| 96 | /// </value>
|
---|
| 97 | public bool IncludeNullExtension
|
---|
| 98 | {
|
---|
| 99 | get
|
---|
| 100 | {
|
---|
| 101 | return _nullExtension;
|
---|
| 102 | }
|
---|
| 103 | set
|
---|
| 104 | {
|
---|
| 105 | _nullExtension = value;
|
---|
| 106 | }
|
---|
| 107 | }
|
---|
| 108 |
|
---|
| 109 | #endregion
|
---|
| 110 |
|
---|
| 111 | #region Public Methods
|
---|
| 112 |
|
---|
| 113 | public static string Convert(object obj)
|
---|
| 114 | {
|
---|
| 115 | XmlXamlWriter writer = new XmlXamlWriter();
|
---|
| 116 |
|
---|
| 117 | return writer.Save(obj);
|
---|
| 118 | }
|
---|
| 119 |
|
---|
| 120 | // Summary:
|
---|
| 121 | // Returns a Extensible Application Markup Language (XAML) string that serializes
|
---|
| 122 | // the provided object.
|
---|
| 123 | //
|
---|
| 124 | // Parameters:
|
---|
| 125 | // obj:
|
---|
| 126 | // The element to be serialized. Typically, this is the root element of a page
|
---|
| 127 | // or application.
|
---|
| 128 | //
|
---|
| 129 | // Returns:
|
---|
| 130 | // Extensible Application Markup Language (XAML) string that can be written
|
---|
| 131 | // to a stream or file. The logical tree of all elements that fall under the
|
---|
| 132 | // provided obj element will be serialized.
|
---|
| 133 | //
|
---|
| 134 | // Exceptions:
|
---|
| 135 | // System.Security.SecurityException:
|
---|
| 136 | // the application is not running in full trust.
|
---|
| 137 | //
|
---|
| 138 | // System.ArgumentNullException:
|
---|
| 139 | // obj is null.
|
---|
| 140 | public string Save(object obj)
|
---|
| 141 | {
|
---|
| 142 | if (obj == null)
|
---|
| 143 | {
|
---|
| 144 | return String.Empty;
|
---|
| 145 | }
|
---|
| 146 |
|
---|
| 147 | if (_contentProperties == null)
|
---|
| 148 | {
|
---|
| 149 | _contentProperties = new Dictionary<Type, string>();
|
---|
| 150 | }
|
---|
| 151 |
|
---|
| 152 | //TODO--PAUL: For now just cheat...
|
---|
| 153 | string nsName = obj.GetType().Namespace;
|
---|
| 154 |
|
---|
| 155 | if (nsName != null && nsName.StartsWith("System.Windows"))
|
---|
| 156 | {
|
---|
| 157 | _namespaceCache.IsFrameworkRoot = true;
|
---|
| 158 | }
|
---|
| 159 |
|
---|
| 160 | ResolveXmlNamespaces(obj);
|
---|
| 161 |
|
---|
| 162 | XmlWriterSettings settings = new XmlWriterSettings();
|
---|
| 163 | settings.Indent = true;
|
---|
| 164 | settings.OmitXmlDeclaration = true;
|
---|
| 165 |
|
---|
| 166 | StringBuilder builder = new StringBuilder();
|
---|
| 167 | StringWriter writer = new StringWriter(builder);
|
---|
| 168 | using (XmlWriter xmlWriter = XmlWriter.Create(writer, settings))
|
---|
| 169 | {
|
---|
| 170 | WriteObject(null, obj, xmlWriter, true);
|
---|
| 171 | }
|
---|
| 172 | writer.Close();
|
---|
| 173 |
|
---|
| 174 | _contentProperties = null;
|
---|
| 175 |
|
---|
| 176 | return builder.ToString();
|
---|
| 177 | }
|
---|
| 178 |
|
---|
| 179 | //
|
---|
| 180 | // Summary:
|
---|
| 181 | // Saves Extensible Application Markup Language (XAML) information into a provided
|
---|
| 182 | // stream to serialize the provided object.
|
---|
| 183 | //
|
---|
| 184 | // Parameters:
|
---|
| 185 | // obj:
|
---|
| 186 | // The element to be serialized. Typically, this is the root element of a page
|
---|
| 187 | // or application.
|
---|
| 188 | //
|
---|
| 189 | // stream:
|
---|
| 190 | // Destination stream for the serialized XAML information.
|
---|
| 191 | //
|
---|
| 192 | // Exceptions:
|
---|
| 193 | // System.Security.SecurityException:
|
---|
| 194 | // the application is not running in full trust.
|
---|
| 195 | //
|
---|
| 196 | // System.ArgumentNullException:
|
---|
| 197 | // obj is null -or- stream is null.
|
---|
| 198 | public void Save(object obj, Stream stream)
|
---|
| 199 | {
|
---|
| 200 | if (obj == null)
|
---|
| 201 | {
|
---|
| 202 | return;
|
---|
| 203 | }
|
---|
| 204 |
|
---|
| 205 | if (_contentProperties == null)
|
---|
| 206 | {
|
---|
| 207 | _contentProperties = new Dictionary<Type, string>();
|
---|
| 208 | }
|
---|
| 209 |
|
---|
| 210 | //TODO--PAUL: For now just cheat...
|
---|
| 211 | string nsName = obj.GetType().Namespace;
|
---|
| 212 |
|
---|
| 213 | if (nsName != null && nsName.StartsWith("System.Windows"))
|
---|
| 214 | {
|
---|
| 215 | _namespaceCache.IsFrameworkRoot = true;
|
---|
| 216 | }
|
---|
| 217 |
|
---|
| 218 | ResolveXmlNamespaces(obj);
|
---|
| 219 |
|
---|
| 220 | XmlWriterSettings settings = new XmlWriterSettings();
|
---|
| 221 | settings.Indent = true;
|
---|
| 222 | settings.OmitXmlDeclaration = true;
|
---|
| 223 |
|
---|
| 224 | using (XmlWriter xmlWriter = XmlWriter.Create(stream, settings))
|
---|
| 225 | {
|
---|
| 226 | WriteObject(null, obj, xmlWriter, true);
|
---|
| 227 | }
|
---|
| 228 |
|
---|
| 229 | _contentProperties = null;
|
---|
| 230 | }
|
---|
| 231 |
|
---|
| 232 | //
|
---|
| 233 | // Summary:
|
---|
| 234 | // Saves Extensible Application Markup Language (XAML) information as the source
|
---|
| 235 | // for a provided text writer object. The output of the text writer can then
|
---|
| 236 | // be used to serialize the provided object.
|
---|
| 237 | //
|
---|
| 238 | // Parameters:
|
---|
| 239 | // writer:
|
---|
| 240 | // TextWriter instance to use to write the serialized XAML information.
|
---|
| 241 | //
|
---|
| 242 | // obj:
|
---|
| 243 | // The element to be serialized. Typically, this is the root element of a page
|
---|
| 244 | // or application.
|
---|
| 245 | //
|
---|
| 246 | // Exceptions:
|
---|
| 247 | // System.ArgumentNullException:
|
---|
| 248 | // obj is null -or- writer is null.
|
---|
| 249 | //
|
---|
| 250 | // System.Security.SecurityException:
|
---|
| 251 | // the application is not running in full trust.
|
---|
| 252 | public void Save(object obj, TextWriter writer)
|
---|
| 253 | {
|
---|
| 254 | if (obj == null)
|
---|
| 255 | {
|
---|
| 256 | return;
|
---|
| 257 | }
|
---|
| 258 |
|
---|
| 259 | if (_contentProperties == null)
|
---|
| 260 | {
|
---|
| 261 | _contentProperties = new Dictionary<Type, string>();
|
---|
| 262 | }
|
---|
| 263 |
|
---|
| 264 | //TODO--PAUL: For now just cheat...
|
---|
| 265 | string nsName = obj.GetType().Namespace;
|
---|
| 266 |
|
---|
| 267 | if (nsName != null && nsName.StartsWith("System.Windows"))
|
---|
| 268 | {
|
---|
| 269 | _namespaceCache.IsFrameworkRoot = true;
|
---|
| 270 | }
|
---|
| 271 |
|
---|
| 272 | ResolveXmlNamespaces(obj);
|
---|
| 273 |
|
---|
| 274 | XmlWriterSettings settings = new XmlWriterSettings();
|
---|
| 275 | settings.Indent = true;
|
---|
| 276 | settings.OmitXmlDeclaration = true;
|
---|
| 277 |
|
---|
| 278 | using (XmlWriter xmlWriter = XmlWriter.Create(writer, settings))
|
---|
| 279 | {
|
---|
| 280 | WriteObject(null, obj, xmlWriter, true);
|
---|
| 281 | }
|
---|
| 282 |
|
---|
| 283 | _contentProperties = null;
|
---|
| 284 | }
|
---|
| 285 |
|
---|
| 286 | //
|
---|
| 287 | // Summary:
|
---|
| 288 | // Saves Extensible Application Markup Language (XAML) information as the source
|
---|
| 289 | // for a provided XML writer object. The output of the XML writer can then be
|
---|
| 290 | // used to serialize the provided object.
|
---|
| 291 | //
|
---|
| 292 | // Parameters:
|
---|
| 293 | // obj:
|
---|
| 294 | // The element to be serialized. Typically, this is the root element of a page
|
---|
| 295 | // or application.
|
---|
| 296 | //
|
---|
| 297 | // xmlWriter:
|
---|
| 298 | // Writer to use to write the serialized XAML information.
|
---|
| 299 | //
|
---|
| 300 | // Exceptions:
|
---|
| 301 | // System.ArgumentNullException:
|
---|
| 302 | // obj is null -or- manager is null.
|
---|
| 303 | //
|
---|
| 304 | // System.Security.SecurityException:
|
---|
| 305 | // the application is not running in full trust.
|
---|
| 306 | public void Save(object obj, XmlWriter xmlWriter)
|
---|
| 307 | {
|
---|
| 308 | if (obj == null)
|
---|
| 309 | {
|
---|
| 310 | return;
|
---|
| 311 | }
|
---|
| 312 |
|
---|
| 313 | if (_contentProperties == null)
|
---|
| 314 | {
|
---|
| 315 | _contentProperties = new Dictionary<Type, string>();
|
---|
| 316 | }
|
---|
| 317 |
|
---|
| 318 | //TODO--PAUL: For now just cheat...
|
---|
| 319 | string nsName = obj.GetType().Namespace;
|
---|
| 320 |
|
---|
| 321 | if (nsName != null && nsName.StartsWith("System.Windows"))
|
---|
| 322 | {
|
---|
| 323 | _namespaceCache.IsFrameworkRoot = true;
|
---|
| 324 | }
|
---|
| 325 |
|
---|
| 326 | ResolveXmlNamespaces(obj);
|
---|
| 327 |
|
---|
| 328 | WriteObject(null, obj, xmlWriter, true);
|
---|
| 329 |
|
---|
| 330 | _contentProperties = null;
|
---|
| 331 | }
|
---|
| 332 |
|
---|
| 333 | #endregion
|
---|
| 334 |
|
---|
| 335 | #region Private Methods
|
---|
| 336 |
|
---|
| 337 | private void WriteObject(object key, object obj, XmlWriter writer, bool isRoot)
|
---|
| 338 | {
|
---|
| 339 | List<MarkupProperty> propertyElements = new List<MarkupProperty>();
|
---|
| 340 | MarkupProperty contentProperty = null;
|
---|
| 341 | string contentPropertyName = null;
|
---|
| 342 | MarkupObject markupObj = MarkupWriter.GetMarkupObjectFor(obj);
|
---|
| 343 | Type objectType = markupObj.ObjectType;
|
---|
| 344 |
|
---|
| 345 | string ns = _namespaceCache.GetNamespaceUriFor(objectType);
|
---|
| 346 | string prefix = _namespaceCache.GetDefaultPrefixFor(ns);
|
---|
| 347 |
|
---|
| 348 | if (isRoot)
|
---|
| 349 | {
|
---|
| 350 | if (String.IsNullOrEmpty(prefix))
|
---|
| 351 | {
|
---|
| 352 | if (String.IsNullOrEmpty(ns))
|
---|
| 353 | {
|
---|
| 354 | writer.WriteStartElement(markupObj.ObjectType.Name, NamespaceCache.DefaultNamespace);
|
---|
| 355 | writer.WriteAttributeString("xmlns",
|
---|
| 356 | NamespaceCache.XmlnsNamespace, NamespaceCache.DefaultNamespace);
|
---|
| 357 | }
|
---|
| 358 | else
|
---|
| 359 | {
|
---|
| 360 | writer.WriteStartElement(markupObj.ObjectType.Name, ns);
|
---|
| 361 | writer.WriteAttributeString("xmlns", NamespaceCache.XmlnsNamespace, ns);
|
---|
| 362 | }
|
---|
| 363 | }
|
---|
| 364 | else
|
---|
| 365 | {
|
---|
| 366 | writer.WriteStartElement(prefix, markupObj.ObjectType.Name, ns);
|
---|
| 367 | }
|
---|
| 368 | writer.WriteAttributeString("xmlns", "x",
|
---|
| 369 | NamespaceCache.XmlnsNamespace, NamespaceCache.XamlNamespace);
|
---|
| 370 |
|
---|
| 371 | foreach (NamespaceMap map in _dicNamespaceMap.Values)
|
---|
| 372 | {
|
---|
| 373 | if (!String.IsNullOrEmpty(map.Prefix) && !String.Equals(map.Prefix, "x"))
|
---|
| 374 | writer.WriteAttributeString("xmlns", map.Prefix, NamespaceCache.XmlnsNamespace, map.XmlNamespace);
|
---|
| 375 | }
|
---|
| 376 | }
|
---|
| 377 | else
|
---|
| 378 | {
|
---|
| 379 | //TODO: Fix - the best way to handle this case...
|
---|
| 380 | if (markupObj.ObjectType.Name == "PathFigureCollection" && markupObj.Instance != null)
|
---|
| 381 | {
|
---|
| 382 | WriteState writeState = writer.WriteState;
|
---|
| 383 |
|
---|
| 384 | if (writeState == WriteState.Element)
|
---|
| 385 | {
|
---|
| 386 | writer.WriteAttributeString("Figures", markupObj.Instance.ToString());
|
---|
| 387 | }
|
---|
| 388 | else
|
---|
| 389 | {
|
---|
| 390 | if (String.IsNullOrEmpty(prefix))
|
---|
| 391 | {
|
---|
| 392 | writer.WriteStartElement("PathGeometry.Figures");
|
---|
| 393 | }
|
---|
| 394 | else
|
---|
| 395 | {
|
---|
| 396 | writer.WriteStartElement("PathGeometry.Figures", ns);
|
---|
| 397 | }
|
---|
| 398 | writer.WriteString(markupObj.Instance.ToString());
|
---|
| 399 | writer.WriteEndElement();
|
---|
| 400 | }
|
---|
| 401 | return;
|
---|
| 402 | }
|
---|
| 403 | else
|
---|
| 404 | {
|
---|
| 405 | if (String.IsNullOrEmpty(prefix))
|
---|
| 406 | {
|
---|
| 407 | writer.WriteStartElement(markupObj.ObjectType.Name);
|
---|
| 408 | }
|
---|
| 409 | else
|
---|
| 410 | {
|
---|
| 411 | writer.WriteStartElement(markupObj.ObjectType.Name, ns);
|
---|
| 412 | }
|
---|
| 413 | }
|
---|
| 414 | }
|
---|
| 415 |
|
---|
| 416 | // Add the x:Name for object like Geometry/Drawing not derived from FrameworkElement...
|
---|
| 417 | DependencyObject dep = obj as DependencyObject;
|
---|
| 418 | if (dep != null)
|
---|
| 419 | {
|
---|
| 420 | string nameValue = dep.GetValue(FrameworkElement.NameProperty) as string;
|
---|
| 421 | if (!String.IsNullOrEmpty(nameValue) && !(dep is FrameworkElement))
|
---|
| 422 | {
|
---|
| 423 | writer.WriteAttributeString("x", "Name", NamespaceCache.XamlNamespace, nameValue);
|
---|
| 424 | }
|
---|
| 425 | }
|
---|
| 426 |
|
---|
| 427 | if (key != null)
|
---|
| 428 | {
|
---|
| 429 | string keyString = key.ToString();
|
---|
| 430 | if (keyString.Length > 0)
|
---|
| 431 | {
|
---|
| 432 | writer.WriteAttributeString("x", "Key", NamespaceCache.XamlNamespace, keyString);
|
---|
| 433 | }
|
---|
| 434 | else
|
---|
| 435 | {
|
---|
| 436 | //TODO: key may not be a string, what about x:Type...
|
---|
| 437 | throw new NotImplementedException(
|
---|
| 438 | "Sample XamlWriter cannot yet handle keys that aren't strings");
|
---|
| 439 | }
|
---|
| 440 | }
|
---|
| 441 |
|
---|
| 442 | //Look for CPA info in our cache that keeps contentProperty names per Type
|
---|
| 443 | //If it doesn't have an entry, go get the info and store it.
|
---|
| 444 | if (!_contentProperties.ContainsKey(objectType))
|
---|
| 445 | {
|
---|
| 446 | string lookedUpContentProperty = String.Empty;
|
---|
| 447 | foreach (Attribute attr in markupObj.Attributes)
|
---|
| 448 | {
|
---|
| 449 | ContentPropertyAttribute cpa = attr as ContentPropertyAttribute;
|
---|
| 450 | if (cpa != null)
|
---|
| 451 | {
|
---|
| 452 | lookedUpContentProperty = cpa.Name;
|
---|
| 453 | //Once content property is found, come out of the loop.
|
---|
| 454 | break;
|
---|
| 455 | }
|
---|
| 456 | }
|
---|
| 457 |
|
---|
| 458 | _contentProperties.Add(objectType, lookedUpContentProperty);
|
---|
| 459 | }
|
---|
| 460 |
|
---|
| 461 | contentPropertyName = _contentProperties[objectType];
|
---|
| 462 | string contentString = String.Empty;
|
---|
| 463 |
|
---|
| 464 | foreach (MarkupProperty markupProperty in markupObj.Properties)
|
---|
| 465 | {
|
---|
| 466 | if (markupProperty.Name != contentPropertyName)
|
---|
| 467 | {
|
---|
| 468 | if (markupProperty.IsValueAsString)
|
---|
| 469 | {
|
---|
| 470 | contentString = markupProperty.Value as string;
|
---|
| 471 | }
|
---|
| 472 | else if (!markupProperty.IsComposite)
|
---|
| 473 | {
|
---|
| 474 | string temp = markupProperty.StringValue;
|
---|
| 475 |
|
---|
| 476 | if (markupProperty.IsAttached)
|
---|
| 477 | {
|
---|
| 478 | string ns1 = _namespaceCache.GetNamespaceUriFor(markupProperty.DependencyProperty.OwnerType);
|
---|
| 479 | string prefix1 = _namespaceCache.GetDefaultPrefixFor(ns1);
|
---|
| 480 |
|
---|
| 481 | if (String.IsNullOrEmpty(prefix1))
|
---|
| 482 | {
|
---|
| 483 | writer.WriteAttributeString(markupProperty.Name, temp);
|
---|
| 484 | }
|
---|
| 485 | else
|
---|
| 486 | {
|
---|
| 487 | writer.WriteAttributeString(markupProperty.Name, ns1, temp);
|
---|
| 488 | }
|
---|
| 489 | }
|
---|
| 490 | else
|
---|
| 491 | {
|
---|
| 492 | if (markupProperty.Name == "FontUri" &&
|
---|
| 493 | (_wpfSettings != null && _wpfSettings.IncludeRuntime))
|
---|
| 494 | {
|
---|
| 495 | string fontUri = temp.ToLower();
|
---|
| 496 | fontUri = fontUri.Replace(_windowsDir, _windowsPath);
|
---|
| 497 |
|
---|
| 498 | StringBuilder builder = new StringBuilder();
|
---|
| 499 | builder.Append("{");
|
---|
| 500 | builder.Append("svg");
|
---|
| 501 | builder.Append(":");
|
---|
| 502 | builder.Append("SvgFontUri ");
|
---|
| 503 | builder.Append(fontUri);
|
---|
| 504 | builder.Append("}");
|
---|
| 505 |
|
---|
| 506 | writer.WriteAttributeString(markupProperty.Name, builder.ToString());
|
---|
| 507 | }
|
---|
| 508 | else
|
---|
| 509 | {
|
---|
| 510 | writer.WriteAttributeString(markupProperty.Name, temp);
|
---|
| 511 | }
|
---|
| 512 | }
|
---|
| 513 | }
|
---|
| 514 | else if (markupProperty.Value.GetType() == _nullType)
|
---|
| 515 | {
|
---|
| 516 | if (_nullExtension)
|
---|
| 517 | {
|
---|
| 518 | writer.WriteAttributeString(markupProperty.Name, "{x:Null}");
|
---|
| 519 | }
|
---|
| 520 | }
|
---|
| 521 | else
|
---|
| 522 | {
|
---|
| 523 | propertyElements.Add(markupProperty);
|
---|
| 524 | }
|
---|
| 525 | }
|
---|
| 526 | else
|
---|
| 527 | {
|
---|
| 528 | contentProperty = markupProperty;
|
---|
| 529 | }
|
---|
| 530 | }
|
---|
| 531 |
|
---|
| 532 | if (contentProperty != null || propertyElements.Count > 0 || contentString != String.Empty)
|
---|
| 533 | {
|
---|
| 534 | foreach (MarkupProperty markupProp in propertyElements)
|
---|
| 535 | {
|
---|
| 536 | string ns2 = _namespaceCache.GetNamespaceUriFor(markupObj.ObjectType);
|
---|
| 537 | string prefix2 = null;
|
---|
| 538 | if (!String.IsNullOrEmpty(ns2))
|
---|
| 539 | {
|
---|
| 540 | prefix2 = _namespaceCache.GetDefaultPrefixFor(ns2);
|
---|
| 541 | }
|
---|
| 542 |
|
---|
| 543 | string propElementName = markupObj.ObjectType.Name + "." + markupProp.Name;
|
---|
| 544 | if (String.IsNullOrEmpty(prefix2))
|
---|
| 545 | {
|
---|
| 546 | writer.WriteStartElement(propElementName);
|
---|
| 547 | }
|
---|
| 548 | else
|
---|
| 549 | {
|
---|
| 550 | writer.WriteStartElement(prefix2, propElementName, ns2);
|
---|
| 551 | }
|
---|
| 552 |
|
---|
| 553 | WriteChildren(writer, markupProp);
|
---|
| 554 | writer.WriteEndElement();
|
---|
| 555 | }
|
---|
| 556 |
|
---|
| 557 | if (contentString != String.Empty)
|
---|
| 558 | {
|
---|
| 559 | writer.WriteValue(contentString);
|
---|
| 560 | }
|
---|
| 561 | else if (contentProperty != null)
|
---|
| 562 | {
|
---|
| 563 | if (contentProperty.Value is string)
|
---|
| 564 | {
|
---|
| 565 | writer.WriteValue(contentProperty.StringValue);
|
---|
| 566 | }
|
---|
| 567 | else
|
---|
| 568 | {
|
---|
| 569 | WriteChildren(writer, contentProperty);
|
---|
| 570 | }
|
---|
| 571 | }
|
---|
| 572 | }
|
---|
| 573 | writer.WriteEndElement();
|
---|
| 574 | }
|
---|
| 575 |
|
---|
| 576 | private void WriteChildren(XmlWriter writer, MarkupProperty markupProp)
|
---|
| 577 | {
|
---|
| 578 | if (!markupProp.IsComposite)
|
---|
| 579 | {
|
---|
| 580 | WriteObject(null, markupProp.Value, writer, false);
|
---|
| 581 | }
|
---|
| 582 | else
|
---|
| 583 | {
|
---|
| 584 | IList collection = markupProp.Value as IList;
|
---|
| 585 | IDictionary dictionary = markupProp.Value as IDictionary;
|
---|
| 586 | if (collection != null)
|
---|
| 587 | {
|
---|
| 588 | foreach (object obj in collection)
|
---|
| 589 | {
|
---|
| 590 | WriteObject(null, obj, writer, false);
|
---|
| 591 | }
|
---|
| 592 | }
|
---|
| 593 | else if (dictionary != null)
|
---|
| 594 | {
|
---|
| 595 | foreach (object key in dictionary.Keys)
|
---|
| 596 | {
|
---|
| 597 | WriteObject(key, dictionary[key], writer, false);
|
---|
| 598 | }
|
---|
| 599 | }
|
---|
| 600 | else
|
---|
| 601 | {
|
---|
| 602 | WriteObject(null, markupProp.Value, writer, false);
|
---|
| 603 | }
|
---|
| 604 | }
|
---|
| 605 | }
|
---|
| 606 |
|
---|
| 607 | private void ResolveXmlNamespaces(object obj)
|
---|
| 608 | {
|
---|
| 609 | List<MarkupProperty> propertyElements = new List<MarkupProperty>();
|
---|
| 610 | MarkupProperty contentProperty = null;
|
---|
| 611 | string contentPropertyName = null;
|
---|
| 612 | MarkupObject markupObj = MarkupWriter.GetMarkupObjectFor(obj);
|
---|
| 613 | Type objectType = markupObj.ObjectType;
|
---|
| 614 |
|
---|
| 615 | string ns = _namespaceCache.GetNamespaceUriFor(objectType);
|
---|
| 616 | if (!String.IsNullOrEmpty(ns))
|
---|
| 617 | {
|
---|
| 618 | string prefix = _namespaceCache.GetDefaultPrefixFor(ns);
|
---|
| 619 | _dicNamespaceMap[ns] = new NamespaceMap(prefix, ns);
|
---|
| 620 | }
|
---|
| 621 |
|
---|
| 622 | //Look for CPA info in our cache that keeps contentProperty names per Type
|
---|
| 623 | //If it doesn't have an entry, go get the info and store it.
|
---|
| 624 | if (!_contentProperties.ContainsKey(objectType))
|
---|
| 625 | {
|
---|
| 626 | string lookedUpContentProperty = String.Empty;
|
---|
| 627 |
|
---|
| 628 | foreach (Attribute attr in markupObj.Attributes)
|
---|
| 629 | {
|
---|
| 630 | ContentPropertyAttribute cpa = attr as ContentPropertyAttribute;
|
---|
| 631 | if (cpa != null)
|
---|
| 632 | {
|
---|
| 633 | lookedUpContentProperty = cpa.Name;
|
---|
| 634 | //Once content property is found, come out of the loop.
|
---|
| 635 | break;
|
---|
| 636 | }
|
---|
| 637 | }
|
---|
| 638 |
|
---|
| 639 | _contentProperties.Add(objectType, lookedUpContentProperty);
|
---|
| 640 | }
|
---|
| 641 |
|
---|
| 642 | contentPropertyName = _contentProperties[objectType];
|
---|
| 643 |
|
---|
| 644 | string contentString = String.Empty;
|
---|
| 645 |
|
---|
| 646 | foreach (MarkupProperty markupProperty in markupObj.Properties)
|
---|
| 647 | {
|
---|
| 648 | if (markupProperty.Name != contentPropertyName)
|
---|
| 649 | {
|
---|
| 650 | if (markupProperty.IsValueAsString)
|
---|
| 651 | {
|
---|
| 652 | contentString = markupProperty.Value as string;
|
---|
| 653 | }
|
---|
| 654 | else if (!markupProperty.IsComposite)
|
---|
| 655 | {
|
---|
| 656 | //Bug Fix DX-0120123
|
---|
| 657 | if (markupProperty.DependencyProperty != null)
|
---|
| 658 | {
|
---|
| 659 | string ns1 = _namespaceCache.GetNamespaceUriFor(
|
---|
| 660 | markupProperty.DependencyProperty.OwnerType);
|
---|
| 661 | string prefix1 = _namespaceCache.GetDefaultPrefixFor(ns1);
|
---|
| 662 |
|
---|
| 663 | if (!String.IsNullOrEmpty(prefix1))
|
---|
| 664 | {
|
---|
| 665 | _dicNamespaceMap[ns1] = new NamespaceMap(prefix1, ns1);
|
---|
| 666 | }
|
---|
| 667 | }
|
---|
| 668 | }
|
---|
| 669 | else if (markupProperty.Value.GetType() == _nullType)
|
---|
| 670 | {
|
---|
| 671 | }
|
---|
| 672 | else
|
---|
| 673 | {
|
---|
| 674 | propertyElements.Add(markupProperty);
|
---|
| 675 | }
|
---|
| 676 | }
|
---|
| 677 | else
|
---|
| 678 | {
|
---|
| 679 | contentProperty = markupProperty;
|
---|
| 680 | }
|
---|
| 681 | }
|
---|
| 682 |
|
---|
| 683 | if (contentProperty != null || propertyElements.Count > 0 || contentString != String.Empty)
|
---|
| 684 | {
|
---|
| 685 | foreach (MarkupProperty markupProp in propertyElements)
|
---|
| 686 | {
|
---|
| 687 | string ns2 = _namespaceCache.GetNamespaceUriFor(markupObj.ObjectType);
|
---|
| 688 | if (!String.IsNullOrEmpty(ns2))
|
---|
| 689 | {
|
---|
| 690 | string prefix2 = _namespaceCache.GetDefaultPrefixFor(ns2);
|
---|
| 691 | _dicNamespaceMap[ns2] = new NamespaceMap(prefix2, ns2);
|
---|
| 692 | }
|
---|
| 693 | ResolveChildXmlNamespaces(markupProp);
|
---|
| 694 | }
|
---|
| 695 |
|
---|
| 696 | if (contentProperty != null)
|
---|
| 697 | {
|
---|
| 698 | if (!(contentProperty.Value is String))
|
---|
| 699 | {
|
---|
| 700 | ResolveChildXmlNamespaces(contentProperty);
|
---|
| 701 | }
|
---|
| 702 | }
|
---|
| 703 | }
|
---|
| 704 | }
|
---|
| 705 |
|
---|
| 706 | private void ResolveChildXmlNamespaces(MarkupProperty markupProp)
|
---|
| 707 | {
|
---|
| 708 | if (!markupProp.IsComposite)
|
---|
| 709 | {
|
---|
| 710 | ResolveXmlNamespaces(markupProp);
|
---|
| 711 | }
|
---|
| 712 | else
|
---|
| 713 | {
|
---|
| 714 | IList collection = markupProp.Value as IList;
|
---|
| 715 | IDictionary dictionary = markupProp.Value as IDictionary;
|
---|
| 716 | if (collection != null)
|
---|
| 717 | {
|
---|
| 718 | foreach (object obj in collection)
|
---|
| 719 | {
|
---|
| 720 | ResolveXmlNamespaces(obj);
|
---|
| 721 | }
|
---|
| 722 | }
|
---|
| 723 | else if (dictionary != null)
|
---|
| 724 | {
|
---|
| 725 | foreach (object key in dictionary.Keys)
|
---|
| 726 | {
|
---|
| 727 | ResolveXmlNamespaces(dictionary[key]);
|
---|
| 728 | }
|
---|
| 729 | }
|
---|
| 730 | else
|
---|
| 731 | {
|
---|
| 732 | ResolveXmlNamespaces(markupProp.Value);
|
---|
| 733 | }
|
---|
| 734 | }
|
---|
| 735 | }
|
---|
| 736 |
|
---|
| 737 | #endregion
|
---|
| 738 |
|
---|
| 739 | #region NamespaceCache Class
|
---|
| 740 |
|
---|
| 741 | private sealed class NamespaceCache
|
---|
| 742 | {
|
---|
| 743 | public const string XamlNamespace = "http://schemas.microsoft.com/winfx/2006/xaml";
|
---|
| 744 | public const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
|
---|
| 745 | public const string DefaultNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
|
---|
| 746 | public const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/";
|
---|
| 747 |
|
---|
| 748 | public const string ClrNamespace = "clr-namespace:";
|
---|
| 749 |
|
---|
| 750 | private bool _isFrameworkRoot;
|
---|
| 751 | private Dictionary<string, string> _defaultPrefixes;
|
---|
| 752 | private Dictionary<Assembly, Dictionary<string, string>> _xmlnsDefinitions;
|
---|
| 753 |
|
---|
| 754 | public NamespaceCache()
|
---|
| 755 | {
|
---|
| 756 | _defaultPrefixes = new Dictionary<string, string>();
|
---|
| 757 | _xmlnsDefinitions = new Dictionary<Assembly, Dictionary<string, string>>();
|
---|
| 758 | }
|
---|
| 759 |
|
---|
| 760 | public bool IsFrameworkRoot
|
---|
| 761 | {
|
---|
| 762 | get
|
---|
| 763 | {
|
---|
| 764 | return _isFrameworkRoot;
|
---|
| 765 | }
|
---|
| 766 | set
|
---|
| 767 | {
|
---|
| 768 | _isFrameworkRoot = value;
|
---|
| 769 | }
|
---|
| 770 | }
|
---|
| 771 |
|
---|
| 772 | public string GetDefaultPrefixFor(string uri)
|
---|
| 773 | {
|
---|
| 774 | string uriPrefix;
|
---|
| 775 | _defaultPrefixes.TryGetValue(uri, out uriPrefix);
|
---|
| 776 | if (uriPrefix != null)
|
---|
| 777 | {
|
---|
| 778 | return uriPrefix;
|
---|
| 779 | }
|
---|
| 780 | uriPrefix = "assembly";
|
---|
| 781 | if (!uri.StartsWith(ClrNamespace, StringComparison.OrdinalIgnoreCase))
|
---|
| 782 | {
|
---|
| 783 | return uriPrefix;
|
---|
| 784 | }
|
---|
| 785 | string assNamespace = uri.Substring(ClrNamespace.Length, uri.IndexOf(";",
|
---|
| 786 | StringComparison.OrdinalIgnoreCase) - ClrNamespace.Length);
|
---|
| 787 | if (!String.IsNullOrEmpty(assNamespace))
|
---|
| 788 | {
|
---|
| 789 | StringBuilder builder = new StringBuilder();
|
---|
| 790 | for (int i = 0; i < assNamespace.Length; i++)
|
---|
| 791 | {
|
---|
| 792 | char ch = assNamespace[i];
|
---|
| 793 | if ((ch >= 'A') && (ch <= 'Z'))
|
---|
| 794 | {
|
---|
| 795 | builder.Append(ch.ToString().ToLower());
|
---|
| 796 | }
|
---|
| 797 | }
|
---|
| 798 | if (builder.Length > 0)
|
---|
| 799 | {
|
---|
| 800 | uriPrefix = builder.ToString();
|
---|
| 801 | }
|
---|
| 802 | }
|
---|
| 803 |
|
---|
| 804 | return uriPrefix;
|
---|
| 805 | }
|
---|
| 806 |
|
---|
| 807 | public string GetNamespaceUriFor(Type type)
|
---|
| 808 | {
|
---|
| 809 | string typeNamespace = String.Empty;
|
---|
| 810 | if (type.Namespace == null)
|
---|
| 811 | {
|
---|
| 812 | return String.Format(CultureInfo.InvariantCulture, "clr-namespace:;assembly={0}",
|
---|
| 813 | new object[] { type.Assembly.GetName().Name });
|
---|
| 814 | }
|
---|
| 815 | if (!GetMappingsFor(type.Assembly).TryGetValue(type.Namespace, out typeNamespace))
|
---|
| 816 | {
|
---|
| 817 | if (!String.Equals(type.Namespace, "System.Windows.Markup.Primitives"))
|
---|
| 818 | {
|
---|
| 819 | typeNamespace = String.Format(CultureInfo.InvariantCulture,
|
---|
| 820 | "clr-namespace:{0};assembly={1}", new object[] { type.Namespace,
|
---|
| 821 | type.Assembly.GetName().Name });
|
---|
| 822 | }
|
---|
| 823 | }
|
---|
| 824 |
|
---|
| 825 | return typeNamespace;
|
---|
| 826 | }
|
---|
| 827 |
|
---|
| 828 | public static string GetAssemblyNameFromType(Type type)
|
---|
| 829 | {
|
---|
| 830 | string[] names = type.Assembly.FullName.Split(',');
|
---|
| 831 | if (names.Length > 0)
|
---|
| 832 | {
|
---|
| 833 | return names[0];
|
---|
| 834 | }
|
---|
| 835 |
|
---|
| 836 | return String.Empty;
|
---|
| 837 | }
|
---|
| 838 |
|
---|
| 839 | private Dictionary<string, string> GetMappingsFor(Assembly assembly)
|
---|
| 840 | {
|
---|
| 841 | Dictionary<string, string> dictionary;
|
---|
| 842 | if (_xmlnsDefinitions.TryGetValue(assembly, out dictionary))
|
---|
| 843 | {
|
---|
| 844 | return dictionary;
|
---|
| 845 | }
|
---|
| 846 | foreach (XmlnsPrefixAttribute attribute in assembly.GetCustomAttributes(
|
---|
| 847 | typeof(XmlnsPrefixAttribute), true))
|
---|
| 848 | {
|
---|
| 849 | _defaultPrefixes[attribute.XmlNamespace] = attribute.Prefix;
|
---|
| 850 | }
|
---|
| 851 | //TODO--PAUL: For now just cheat...
|
---|
| 852 | if (_isFrameworkRoot)
|
---|
| 853 | {
|
---|
| 854 | _defaultPrefixes[DefaultNamespace] = String.Empty;
|
---|
| 855 | }
|
---|
| 856 |
|
---|
| 857 | dictionary = new Dictionary<string, string>();
|
---|
| 858 | _xmlnsDefinitions[assembly] = dictionary;
|
---|
| 859 | foreach (XmlnsDefinitionAttribute attribute in assembly.GetCustomAttributes(
|
---|
| 860 | typeof(XmlnsDefinitionAttribute), true))
|
---|
| 861 | {
|
---|
| 862 | if (attribute.AssemblyName == null)
|
---|
| 863 | {
|
---|
| 864 | string prefix1 = null;
|
---|
| 865 | string prefix2 = null;
|
---|
| 866 | string prefix3 = null;
|
---|
| 867 | if (dictionary.TryGetValue(attribute.ClrNamespace, out prefix1) &&
|
---|
| 868 | _defaultPrefixes.TryGetValue(prefix1, out prefix2))
|
---|
| 869 | {
|
---|
| 870 | _defaultPrefixes.TryGetValue(attribute.XmlNamespace, out prefix3);
|
---|
| 871 | }
|
---|
| 872 | if (((prefix1 == null) || (prefix2 == null)) ||
|
---|
| 873 | ((prefix3 != null) && (prefix2.Length > prefix3.Length)))
|
---|
| 874 | {
|
---|
| 875 | dictionary[attribute.ClrNamespace] = attribute.XmlNamespace;
|
---|
| 876 | }
|
---|
| 877 | }
|
---|
| 878 | else
|
---|
| 879 | {
|
---|
| 880 | Assembly nextAssembly = Assembly.Load(new AssemblyName(attribute.AssemblyName));
|
---|
| 881 | if (nextAssembly != null)
|
---|
| 882 | {
|
---|
| 883 | GetMappingsFor(nextAssembly)[attribute.ClrNamespace] = attribute.XmlNamespace;
|
---|
| 884 | }
|
---|
| 885 | }
|
---|
| 886 | }
|
---|
| 887 |
|
---|
| 888 | return dictionary;
|
---|
| 889 | }
|
---|
| 890 | }
|
---|
| 891 |
|
---|
| 892 | #endregion
|
---|
| 893 |
|
---|
| 894 | #region NamespaceMap Class
|
---|
| 895 |
|
---|
| 896 | private sealed class NamespaceMap
|
---|
| 897 | {
|
---|
| 898 | private string _prefix;
|
---|
| 899 | private string _xmlNamespace;
|
---|
| 900 |
|
---|
| 901 | public NamespaceMap(string prefix, string xmlNamespace)
|
---|
| 902 | {
|
---|
| 903 | _prefix = prefix;
|
---|
| 904 | _xmlNamespace = xmlNamespace;
|
---|
| 905 | }
|
---|
| 906 |
|
---|
| 907 | public string Prefix
|
---|
| 908 | {
|
---|
| 909 | get
|
---|
| 910 | {
|
---|
| 911 | return _prefix;
|
---|
| 912 | }
|
---|
| 913 | set
|
---|
| 914 | {
|
---|
| 915 | _prefix = value;
|
---|
| 916 | }
|
---|
| 917 | }
|
---|
| 918 |
|
---|
| 919 | public string XmlNamespace
|
---|
| 920 | {
|
---|
| 921 | get
|
---|
| 922 | {
|
---|
| 923 | return _xmlNamespace;
|
---|
| 924 | }
|
---|
| 925 | set
|
---|
| 926 | {
|
---|
| 927 | _xmlNamespace = value;
|
---|
| 928 | }
|
---|
| 929 | }
|
---|
| 930 | }
|
---|
| 931 |
|
---|
| 932 | #endregion
|
---|
| 933 | }
|
---|
| 934 | }
|
---|