| File: System\Windows\Annotations\LocatorGroup.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // // Description: // ContentLocatorGroup represents a set of Locators. This is used to // model an anchor that is made up of several separately identifiable // pieces such as a set of Visio objects. // // Spec: Simplifying Store Cache Model.doc // using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; using MS.Internal; using MS.Internal.Annotations; namespace System.Windows.Annotations { /// <summary> /// ContentLocatorGroup represents a set of Locators. This is used to /// model an anchor that is made up of several separately identifiable /// pieces such as a set of Visio objects. /// </summary> [XmlRoot(Namespace = AnnotationXmlConstants.Namespaces.CoreSchemaNamespace, ElementName = AnnotationXmlConstants.Elements.ContentLocatorGroup)] public sealed class ContentLocatorGroup : ContentLocatorBase, IXmlSerializable { //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Constructors /// <summary> /// Creates an empty ContentLocatorGroup. /// </summary> public ContentLocatorGroup() { _locators = new AnnotationObservableCollection<ContentLocator>(); _locators.CollectionChanged += OnCollectionChanged; } #endregion Constructors //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Create a deep clone of this ContentLocatorGroup including clones of all /// the Locators it contains. /// </summary> /// <returns>a deep clone of this ContentLocatorGroup; never returns null</returns> public override Object Clone() { ContentLocatorGroup clone = new ContentLocatorGroup(); foreach (ContentLocator loc in _locators) { clone.Locators.Add((ContentLocator)loc.Clone()); } return clone; } #region IXmlSerializable Implementation /// <summary> /// Returns the null. The annotations schema can be found at /// http://schemas.microsoft.com/windows/annotations/2003/11/core. /// </summary> public XmlSchema GetSchema() { return null; } /// <summary> /// Writes the internal data for this ContentLocatorGroup to the writer. This method /// is used by an XmlSerializer to serialize a ContentLocatorGroup. To serialize a /// ContentLocatorGroup to Xml, use an XmlSerializer. /// </summary> /// <param name="writer">the writer to write internal data to</param> /// <exception cref="ArgumentNullException">writer is null</exception> public void WriteXml(XmlWriter writer) { ArgumentNullException.ThrowIfNull(writer); string prefix = writer.LookupPrefix(AnnotationXmlConstants.Namespaces.CoreSchemaNamespace); if (prefix == null) { writer.WriteAttributeString(AnnotationXmlConstants.Prefixes.XmlnsPrefix, AnnotationXmlConstants.Prefixes.CoreSchemaPrefix, null, AnnotationXmlConstants.Namespaces.CoreSchemaNamespace); } foreach (ContentLocatorBase locator in _locators) { if (locator != null) { AnnotationResource.ListSerializer.Serialize(writer, locator); } } } /// <summary> /// Reads the internal data for this ContentLocatorGroup from the reader. This method /// is used by an XmlSerializer to deserialize a ContentLocatorGroup. To deserialize a /// ContentLocatorGroup from Xml, use an XmlSerializer. /// </summary> /// <param name="reader">the reader to read internal data from</param> /// <exception cref="ArgumentNullException">reader is null</exception> public void ReadXml(XmlReader reader) { ArgumentNullException.ThrowIfNull(reader); // We expect no attributes on a "ContentLocatorGroup", // so throw using the name of one of the unexpected attributes Annotation.CheckForNonNamespaceAttribute(reader, AnnotationXmlConstants.Elements.ContentLocatorGroup); if (!reader.IsEmptyElement) { reader.Read(); // Reads the start of the "ContentLocatorGroup" element // Consume everything inside of the ContentLocatorGroup tag. while (!(AnnotationXmlConstants.Elements.ContentLocatorGroup == reader.LocalName && XmlNodeType.EndElement == reader.NodeType)) { // If a child node is a <ContentLocatorBase>, deserialize a ContentLocatorBase if (AnnotationXmlConstants.Elements.ContentLocator == reader.LocalName) { ContentLocator locator = (ContentLocator)AnnotationResource.ListSerializer.Deserialize(reader); _locators.Add(locator); } else { // The ContentLocatorGroup contains a child that is not a ContentLocatorBase or // text. This isn't valid in the schema so we throw. throw new XmlException(SR.Format(SR.InvalidXmlContent, AnnotationXmlConstants.Elements.ContentLocatorGroup)); } } } reader.Read(); // Reads the end of the "ContentLocatorGroup" element (or whole element if empty) } #endregion IXmlSerializable Implementation #endregion Public Methods //------------------------------------------------------ // // Public Operators // //------------------------------------------------------ //------------------------------------------------------ // // Public Events // //------------------------------------------------------ //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region Public Properties /// <summary> /// /// </summary> public Collection<ContentLocator> Locators { get { return _locators; } } #endregion Public Properties //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods /// <summary> /// Merges the ContentLocatorGroup with a ContentLocatorBase. If other is a ContentLocatorBase, /// it is added to the end of every ContentLocatorBase in this ContentLocatorGroup. /// If other is a ContentLocatorGroup, then each ContentLocatorBase in it must be added to /// each ContentLocatorBase (or a clone) in this ContentLocatorGroup. The result is this /// ContentLocatorGroup will contain n*m ContentLocatorBase. /// In both cases, this ContentLocatorGroup is modified. /// </summary> /// <param name="other">other ContentLocatorBase to merge with</param> /// <returns>this ContentLocatorGroup</returns> internal override ContentLocatorBase Merge(ContentLocatorBase other) { if (other == null) return this; ContentLocator firstRight = null; ContentLocatorGroup locatorGroup = other as ContentLocatorGroup; if (locatorGroup != null) { List<ContentLocatorBase> tempList = new List<ContentLocatorBase>(locatorGroup.Locators.Count * (this.Locators.Count - 1)); foreach (ContentLocator left in this.Locators) { foreach (ContentLocator right in locatorGroup.Locators) { if (firstRight == null) { firstRight = right; } else { ContentLocator clone = (ContentLocator)left.Clone(); clone.Append(right); tempList.Add(clone); } } // No need to clone or add here - just use the locator // already in the ContentLocatorGroup left.Append(firstRight); firstRight = null; } foreach (ContentLocator list in tempList) { this.Locators.Add(list); } } else { ContentLocator otherLoc = other as ContentLocator; Invariant.Assert(otherLoc != null, "other should be of type ContentLocator"); // Only other possible type for the ContentLocatorBase foreach(ContentLocator loc in this.Locators) { loc.Append(otherLoc); } } return this; } #endregion Internal Methods //------------------------------------------------------ // // Internal Operators // //------------------------------------------------------ //------------------------------------------------------ // // Internal Events // //------------------------------------------------------ //------------------------------------------------------ // // Internal Properties // //------------------------------------------------------ //------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods /// <summary> /// Listens for change events from the collection of locators. Fires a change event /// from this LocatorSet when an event is received. /// </summary> private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { FireLocatorChanged("Locators"); } #endregion Private Methods //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ #region Private Fields /// <summary> /// Private data structure holding the ContentLocatorBase. /// </summary> private AnnotationObservableCollection<ContentLocator> _locators; #endregion Private Fields } }