Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / System / Windows / Annotations / Annotation.cs / 1 / Annotation.cs
//------------------------------------------------------------------------------ // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // Annotation class is the top-level Object Model class for the // annotation framework. It represents a single annotation with // all of its anchoring and content data. // // Spec: http://team/sites/ag/Specifications/Simplifying%20Store%20Cache%20Model.doc // // History: // 10/04/2002: rruiz: Added header comment to ObjectModel.cs // 07/03/2003: magedz: Renamed Link, LinkSequence to LocatorPart and Locator // respectively. // 05/31/2003: LGolding: Ported to WCP tree. // 07/15/2003: rruiz: Rewrote implementations to extend abstract classes // instead of implement interfaces; got rid of obsolete // classes; put each class in separate file. // 12/03/2003: ssimova: Changed Contexts to Anchors // 6/30/2004: rruiz: Made the class concrete, changed the APIs to be more // typesafe, made the class XML serializable. // //----------------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Windows.Annotations.Storage; using System.Windows.Data; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; using MS.Internal; using MS.Internal.Annotations; using MS.Utility; namespace System.Windows.Annotations { ////// Actions that can be taken on subparts of an /// Annotation - authors, anchors, and cargos. /// public enum AnnotationAction { ////// The subpart was added to the Annotation. /// Added, ////// The subpart was removed from the Annotation. /// Removed, ////// The subpart already is part of the Annotation and was modified. /// Modified } ////// Annotation class is the top-level Object Model class for the /// annotation framework. It represents a single annotation with /// all of its anchoring and content data. /// [XmlRoot(Namespace = AnnotationXmlConstants.Namespaces.CoreSchemaNamespace, ElementName = AnnotationXmlConstants.Elements.Annotation)] public sealed class Annotation : IXmlSerializable { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors ////// Creates an instance of Annotation for use by XML serialization. /// This constructor should not be used directly. It does not /// initialize the instance. /// public Annotation() { // Should only be used from XML serialization. This instance will // not be a valid Annotation if used outside of serialization. _id = Guid.Empty; _created = DateTime.MinValue; _modified = DateTime.MinValue; Init(); } ////// Creates an instance of Annotation with the specified type name. /// /// fully qualified type name of the new Annotation ///annotationType is null ///annotationType's Name or Namespace is null or empty string public Annotation(XmlQualifiedName annotationType) { if (annotationType == null) { throw new ArgumentNullException("annotationType"); } if (String.IsNullOrEmpty(annotationType.Name)) { throw new ArgumentException(SR.Get(SRID.TypeNameMustBeSpecified), "annotationType.Name");//todo better message } if (String.IsNullOrEmpty(annotationType.Namespace)) { throw new ArgumentException(SR.Get(SRID.TypeNameMustBeSpecified), "annotationType.Namespace");//todo better message } _id = Guid.NewGuid(); _typeName = annotationType; // For an new instance of Annotation, _created should be == with _modified _created = DateTime.Now; _modified = _created; Init(); } ////// Creates an instance of Annotation with the values provided. This /// constructor is for use by stores using their own serialization method. /// It provides a way to create an annotation with all the necessary /// read-only data. /// /// the fully qualified type name of the new Annotation /// the id of the new Annotation /// the time the annotation was first created /// the time the annotation was last modified ///annotationType is null ///lastModificationTime is earlier than creationTime ///annotationType's Name or Namespace is null or empty string ///id is equal to Guid.Empty public Annotation(XmlQualifiedName annotationType, Guid id, DateTime creationTime, DateTime lastModificationTime) { if (annotationType == null) { throw new ArgumentNullException("annotationType"); } if (String.IsNullOrEmpty(annotationType.Name)) { throw new ArgumentException(SR.Get(SRID.TypeNameMustBeSpecified), "annotationType.Name");//todo better message } if (String.IsNullOrEmpty(annotationType.Namespace)) { throw new ArgumentException(SR.Get(SRID.TypeNameMustBeSpecified), "annotationType.Namespace");//todo better message } if (id.Equals(Guid.Empty)) { throw new ArgumentException(SR.Get(SRID.InvalidGuid), "id"); } if (lastModificationTime.CompareTo(creationTime) < 0) { throw new ArgumentException(SR.Get(SRID.ModificationEarlierThanCreation), "lastModificationTime"); } _id = id; _typeName = annotationType; _created = creationTime; _modified = lastModificationTime; Init(); } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods #region IXmlSerializable Implementation ////// Returns null. The annotations schema is available at /// http://schemas.microsoft.com/windows/annotations/2003/11/core. /// public XmlSchema GetSchema() { return null; } ////// Serializes this Annotation to XML with the passed in XmlWriter. /// /// the writer to serialize the Annotation to ///writer is null public void WriteXml(XmlWriter writer) { if (writer == null) { throw new ArgumentNullException("writer"); } //fire trace event EventTrace.NormalTraceEvent(EventTraceGuidId.SERIALIZEANNOTATIONGUID, EventType.StartEvent); if (String.IsNullOrEmpty(writer.LookupPrefix(AnnotationXmlConstants.Namespaces.CoreSchemaNamespace))) { writer.WriteAttributeString(AnnotationXmlConstants.Prefixes.XmlnsPrefix, AnnotationXmlConstants.Prefixes.CoreSchemaPrefix, null, AnnotationXmlConstants.Namespaces.CoreSchemaNamespace); } if (String.IsNullOrEmpty(writer.LookupPrefix(AnnotationXmlConstants.Namespaces.BaseSchemaNamespace))) { writer.WriteAttributeString(AnnotationXmlConstants.Prefixes.XmlnsPrefix, AnnotationXmlConstants.Prefixes.BaseSchemaPrefix, null, AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); } if (_typeName == null) { throw new InvalidOperationException(SR.Get(SRID.CannotSerializeInvalidInstance)); } // XmlConvert.ToString is [Obsolete] #pragma warning disable 0618 writer.WriteAttributeString(AnnotationXmlConstants.Attributes.Id, XmlConvert.ToString(_id)); writer.WriteAttributeString(AnnotationXmlConstants.Attributes.CreationTime, XmlConvert.ToString(_created)); writer.WriteAttributeString(AnnotationXmlConstants.Attributes.LastModificationTime, XmlConvert.ToString(_modified)); #pragma warning restore 0618 writer.WriteStartAttribute(AnnotationXmlConstants.Attributes.TypeName); writer.WriteQualifiedName(_typeName.Name, _typeName.Namespace); writer.WriteEndAttribute(); if (_authors != null && _authors.Count > 0) { writer.WriteStartElement(AnnotationXmlConstants.Elements.AuthorCollection, AnnotationXmlConstants.Namespaces.CoreSchemaNamespace); foreach (string author in _authors) { if (author != null) { writer.WriteElementString(AnnotationXmlConstants.Prefixes.BaseSchemaPrefix, AnnotationXmlConstants.Elements.StringAuthor, AnnotationXmlConstants.Namespaces.BaseSchemaNamespace, author); } } writer.WriteEndElement(); } if (_anchors != null && _anchors.Count > 0) { writer.WriteStartElement(AnnotationXmlConstants.Elements.AnchorCollection, AnnotationXmlConstants.Namespaces.CoreSchemaNamespace); foreach (AnnotationResource anchor in _anchors) { if (anchor != null) { ResourceSerializer.Serialize(writer, anchor); } } writer.WriteEndElement(); } if (_cargos != null && _cargos.Count > 0) { writer.WriteStartElement(AnnotationXmlConstants.Elements.CargoCollection, AnnotationXmlConstants.Namespaces.CoreSchemaNamespace); foreach (AnnotationResource cargo in _cargos) { if (cargo != null) { ResourceSerializer.Serialize(writer, cargo); } } writer.WriteEndElement(); } //fire trace event EventTrace.NormalTraceEvent(EventTraceGuidId.SERIALIZEANNOTATIONGUID, EventType.EndEvent); } ////// Deserializes an Annotation from the XmlReader passed in. /// /// reader to deserialize from ///reader is null public void ReadXml(XmlReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } //fire trace event EventTrace.NormalTraceEvent(EventTraceGuidId.DESERIALIZEANNOTATIONGUID, EventType.StartEvent); XmlDocument doc = new XmlDocument(); ReadAttributes(reader); if (!reader.IsEmptyElement) { reader.Read(); // Read the remainder of the "Annotation" start tag while (!(XmlNodeType.EndElement == reader.NodeType && AnnotationXmlConstants.Elements.Annotation == reader.LocalName)) { if (AnnotationXmlConstants.Elements.AnchorCollection == reader.LocalName) { CheckForNonNamespaceAttribute(reader, AnnotationXmlConstants.Elements.AnchorCollection); if (!reader.IsEmptyElement) { reader.Read(); // Reads the "Anchors" start tag while (!(AnnotationXmlConstants.Elements.AnchorCollection == reader.LocalName && XmlNodeType.EndElement == reader.NodeType)) { AnnotationResource anchor = (AnnotationResource)ResourceSerializer.Deserialize(reader); _anchors.Add(anchor); } } reader.Read(); // Reads the "Anchors" end tag (or whole tag if it was empty) } else if (AnnotationXmlConstants.Elements.CargoCollection == reader.LocalName) { CheckForNonNamespaceAttribute(reader, AnnotationXmlConstants.Elements.CargoCollection); if (!reader.IsEmptyElement) { reader.Read(); // Reads the "Cargos" start tag while (!(AnnotationXmlConstants.Elements.CargoCollection == reader.LocalName && XmlNodeType.EndElement == reader.NodeType)) { AnnotationResource cargo = (AnnotationResource)ResourceSerializer.Deserialize(reader); _cargos.Add(cargo); } } reader.Read(); // Reads the "Cargos" end tag (or whole tag if it was empty) } else if (AnnotationXmlConstants.Elements.AuthorCollection == reader.LocalName) { CheckForNonNamespaceAttribute(reader, AnnotationXmlConstants.Elements.AuthorCollection); if (!reader.IsEmptyElement) { reader.Read(); // Reads the "Authors" start tag while (!(AnnotationXmlConstants.Elements.AuthorCollection == reader.LocalName && XmlNodeType.EndElement == reader.NodeType)) { if (!(AnnotationXmlConstants.Elements.StringAuthor == reader.LocalName && XmlNodeType.Element == reader.NodeType)) { throw new XmlException(SR.Get(SRID.InvalidXmlContent, AnnotationXmlConstants.Elements.Annotation)); } XmlNode node = doc.ReadNode(reader); // Reads the entire "StringAuthor" tag if (!reader.IsEmptyElement) { _authors.Add(node.InnerText); } } } reader.Read(); // Reads the "Authors" end tag (or whole tag if it was empty) } else { // The annotation must contain some invalid content which is not part of the schema. throw new XmlException(SR.Get(SRID.InvalidXmlContent, AnnotationXmlConstants.Elements.Annotation)); } } } reader.Read(); // Read the end of the "Annotation" tag (or the whole tag if its empty) //fire trace event EventTrace.NormalTraceEvent(EventTraceGuidId.DESERIALIZEANNOTATIONGUID, EventType.EndEvent); } #endregion IXmlSerializable Implementation #endregion Public Methods //------------------------------------------------------ // // Public Operators // //------------------------------------------------------ //----------------------------------------------------- // // Public Events // //------------------------------------------------------ #region Public Events ////// Event fired when an author is added, removed or modified in anyway. /// public event AnnotationAuthorChangedEventHandler AuthorChanged; ////// Event fired when an anchor is added, removed or modified in anyway. /// This includes modifications to an anchor's sub-parts such as /// changing a value on a ContentLocatorPart which is contained by a ContentLocatorBase /// which is contained by an anchor which is contained by this /// Annotation. /// public event AnnotationResourceChangedEventHandler AnchorChanged; ////// Event fired when an cargo is added, removed or modified in anyway. /// This includes modifications to a cargo's sub-parts such as /// changing an attribute on an XmlNode contained by a content which /// is contained by a cargo which is contained by this Annotation. /// public event AnnotationResourceChangedEventHandler CargoChanged; #endregion Public Events //----------------------------------------------------- // // Public Properties // //----------------------------------------------------- #region Public Properties ////// An Annotation is given a unique Guid when it is first instantiated. /// ///the unique id of this Annotation; this property will return /// Guid.Empty if the Annotation was instantied with the default constructor - /// which should not be used directly public Guid Id { get { return _id; } } ////// The type of this Annotation. /// ///the type of this Annotation; this property will only return /// null if the Annotation was instantiated with the default constructor - which /// should not be used directly public XmlQualifiedName AnnotationType { get { return _typeName; } } ////// The time of creation for this Annotation. This is set when /// the Annotation is first instantiated. /// ///the creation time of this Annotation; this property will return /// DateTime.MinValue if the Annotation was instantiated with the default constructor - /// which should not be used directly public DateTime CreationTime { get { return _created; } } ////// The time of the Annotation was last modified. This is set after any /// change to Annotation before any notifications are fired. /// ///the last modification time of this Annotation; this property will /// return DateTime.MinValue if the Annotation was instantiated with the default /// constructor - which should not be used directly public DateTime LastModificationTime { get { return _modified; } } ////// The collection of zero or more authors for this Annotation. /// ///collection of authors for this Annotation; never returns null public CollectionAuthors { get { return _authors; } } /// /// The collection of zero or more Resources that represent the anchors /// of this Annotation. These could be references to content, /// actually include the content itself, or both (as in the case of /// a snippet being the anchor of a comment). /// ///collection of Resources; never returns null public CollectionAnchors { get { return _anchors; } } /// /// The collection of zero or more Resources that represent the cargos /// of this Annotation. These could be references to content, /// actually include the content itself, or both (as in the case of /// a snippet from a web-page being the cargo). /// ///collection of Resources; never returns null public CollectionCargos { get { return _cargos; } } #endregion Public Properties //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ #region Internal Methods /// /// Returns true if the reader is positioned on an attribute that /// is a namespace attribute - for instance xmlns="xx", xmlns:bac="http:bac", /// or xml:lang="en-us". /// internal static bool IsNamespaceDeclaration(XmlReader reader) { Invariant.Assert(reader != null); // The reader is on a namespace declaration if: // - the current node is an attribute AND either // - the attribute has no prefix and local name is 'xmlns' // - the attribute's prefix is 'xmlns' or 'xml' if (reader.NodeType == XmlNodeType.Attribute) { if (reader.Prefix.Length == 0) { if (reader.LocalName == AnnotationXmlConstants.Prefixes.XmlnsPrefix) return true; } else { if (reader.Prefix == AnnotationXmlConstants.Prefixes.XmlnsPrefix || reader.Prefix == AnnotationXmlConstants.Prefixes.XmlPrefix) return true; } } return false; } ////// Checks all attributes for the current node. If any attribute isn't a /// namespace attribute an exception is thrown. /// internal static void CheckForNonNamespaceAttribute(XmlReader reader, string elementName) { Invariant.Assert(reader != null, "No reader supplied."); Invariant.Assert(elementName != null, "No element name supplied."); while (reader.MoveToNextAttribute()) { // If the attribute is a namespace declaration we should ignore it if (Annotation.IsNamespaceDeclaration(reader)) { continue; } throw new XmlException(SR.Get(SRID.UnexpectedAttribute, reader.LocalName, elementName)); } // We need to move the reader back to the original element the // attributes are on for the next reader operation. Has no effect // if no attributes were looked at reader.MoveToContent(); } #endregion Internal Methods //----------------------------------------------------- // // Private Properties // //------------------------------------------------------ #region Private Properties ////// Returns serializer for Resource objects. Lazily creates /// the serializer for cases where its not needed. /// private static Serializer ResourceSerializer { get { if (_ResourceSerializer == null) { _ResourceSerializer = new Serializer(typeof(AnnotationResource)); } return _ResourceSerializer; } } #endregion Private Properties //------------------------------------------------------ // // Private Methods // //----------------------------------------------------- #region Private Methods private void ReadAttributes(XmlReader reader) { Invariant.Assert(reader != null, "No reader passed in."); // Read all the attributes while (reader.MoveToNextAttribute()) { string value = reader.Value; // Skip null and empty values - they will be treated the // same as if they weren't specified at all if (String.IsNullOrEmpty(value)) continue; switch (reader.LocalName) { case AnnotationXmlConstants.Attributes.Id: _id = XmlConvert.ToGuid(value); break; // XmlConvert.ToDateTime is [Obsolete] #pragma warning disable 0618 case AnnotationXmlConstants.Attributes.CreationTime: _created = XmlConvert.ToDateTime(value); break; case AnnotationXmlConstants.Attributes.LastModificationTime: _modified = XmlConvert.ToDateTime(value); break; #pragma warning restore 0618 case AnnotationXmlConstants.Attributes.TypeName: string[] typeName = value.Split(_Colon); if (typeName.Length == 1) { typeName[0] = typeName[0].Trim(); if (String.IsNullOrEmpty(typeName[0])) { // Just a string of whitespace (empty string doesn't get processed) throw new FormatException(SR.Get(SRID.InvalidAttributeValue, AnnotationXmlConstants.Attributes.TypeName)); } _typeName = new XmlQualifiedName(typeName[0]); } else if (typeName.Length == 2) { typeName[0] = typeName[0].Trim(); typeName[1] = typeName[1].Trim(); if (String.IsNullOrEmpty(typeName[0]) || String.IsNullOrEmpty(typeName[1])) { // One colon, prefix or suffix is empty string or whitespace throw new FormatException(SR.Get(SRID.InvalidAttributeValue, AnnotationXmlConstants.Attributes.TypeName)); } _typeName = new XmlQualifiedName(typeName[1], reader.LookupNamespace(typeName[0])); } else { // More than one colon throw new FormatException(SR.Get(SRID.InvalidAttributeValue, AnnotationXmlConstants.Attributes.TypeName)); } break; default: if (!Annotation.IsNamespaceDeclaration(reader)) throw new XmlException(SR.Get(SRID.UnexpectedAttribute, reader.LocalName, AnnotationXmlConstants.Elements.Annotation)); break; } } // Test to see if any required attribute was missing if (_id.Equals(Guid.Empty)) { throw new XmlException(SR.Get(SRID.RequiredAttributeMissing, AnnotationXmlConstants.Attributes.Id, AnnotationXmlConstants.Elements.Annotation)); } if (_created.Equals(DateTime.MinValue)) { throw new XmlException(SR.Get(SRID.RequiredAttributeMissing, AnnotationXmlConstants.Attributes.CreationTime, AnnotationXmlConstants.Elements.Annotation)); } if (_modified.Equals(DateTime.MinValue)) { throw new XmlException(SR.Get(SRID.RequiredAttributeMissing, AnnotationXmlConstants.Attributes.LastModificationTime, AnnotationXmlConstants.Elements.Annotation)); } if (_typeName == null) { throw new XmlException(SR.Get(SRID.RequiredAttributeMissing, AnnotationXmlConstants.Attributes.TypeName, AnnotationXmlConstants.Elements.Annotation)); } // Move back to the parent "Annotation" element reader.MoveToContent(); } private void OnCargoChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { FireResourceEvent((AnnotationResource)sender, AnnotationAction.Modified, CargoChanged); } private void OnCargosChanged(object sender, NotifyCollectionChangedEventArgs e) { AnnotationAction action = AnnotationAction.Added; IList changedItems = null; switch (e.Action) { case NotifyCollectionChangedAction.Add: action = AnnotationAction.Added; changedItems = e.NewItems; break; case NotifyCollectionChangedAction.Remove: action = AnnotationAction.Removed; changedItems = e.OldItems; break; case NotifyCollectionChangedAction.Replace: // For Replace we need to fire removes and adds. As in other // event firing code - if a listener for one event throws the // rest of the events won't be fired. foreach (AnnotationResource cargo in e.OldItems) { FireResourceEvent(cargo, AnnotationAction.Removed, CargoChanged); } changedItems = e.NewItems; break; case NotifyCollectionChangedAction.Move: // ignore - this only happens on sort break; case NotifyCollectionChangedAction.Reset: // ignore - this only happens on sort break; default: throw new NotSupportedException(SR.Get(SRID.UnexpectedCollectionChangeAction, e.Action)); } if (changedItems != null) { foreach (AnnotationResource cargo in changedItems) { FireResourceEvent(cargo, action, CargoChanged); } } } private void OnAnchorChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { FireResourceEvent((AnnotationResource)sender, AnnotationAction.Modified, AnchorChanged); } private void OnAnchorsChanged(object sender, NotifyCollectionChangedEventArgs e) { AnnotationAction action = AnnotationAction.Added; IList changedItems = null; switch (e.Action) { case NotifyCollectionChangedAction.Add: action = AnnotationAction.Added; changedItems = e.NewItems; break; case NotifyCollectionChangedAction.Remove: action = AnnotationAction.Removed; changedItems = e.OldItems; break; case NotifyCollectionChangedAction.Replace: // For Replace we need to fire removes and adds. As in other // event firing code - if a listener for one event throws the // rest of the events won't be fired. foreach (AnnotationResource anchor in e.OldItems) { FireResourceEvent(anchor, AnnotationAction.Removed, AnchorChanged); } changedItems = e.NewItems; break; case NotifyCollectionChangedAction.Move: // ignore - this only happens on sort break; case NotifyCollectionChangedAction.Reset: // ignore - this only happens on sort break; default: throw new NotSupportedException(SR.Get(SRID.UnexpectedCollectionChangeAction, e.Action)); } if (changedItems != null) { foreach (AnnotationResource anchor in changedItems) { FireResourceEvent(anchor, action, AnchorChanged); } } } private void OnAuthorsChanged(object sender, NotifyCollectionChangedEventArgs e) { AnnotationAction action = AnnotationAction.Added; IList changedItems = null; switch (e.Action) { case NotifyCollectionChangedAction.Add: action = AnnotationAction.Added; changedItems = e.NewItems; break; case NotifyCollectionChangedAction.Remove: action = AnnotationAction.Removed; changedItems = e.OldItems; break; case NotifyCollectionChangedAction.Replace: // For Replace we need to fire removes and adds. As in other // event firing code - if a listener for one event throws the // rest of the events won't be fired. foreach (string author in e.OldItems) { FireAuthorEvent(author, AnnotationAction.Removed); } changedItems = e.NewItems; break; case NotifyCollectionChangedAction.Move: // ignore - this only happens on sort break; case NotifyCollectionChangedAction.Reset: // ignore - this only happens on sort break; default: throw new NotSupportedException(SR.Get(SRID.UnexpectedCollectionChangeAction, e.Action)); } if (changedItems != null) { foreach (Object author in changedItems) { FireAuthorEvent(author, action); } } } ////// Fires an AuthorChanged event for the given author and action. /// /// the author to notify about /// the action that took place for that author private void FireAuthorEvent(Object author, AnnotationAction action) { // 'author' can be null because null authors are allowed in the collection Invariant.Assert(action >= AnnotationAction.Added && action <= AnnotationAction.Modified, "Unknown AnnotationAction"); // Always update the modification time before firing change events _modified = DateTime.Now; if (AuthorChanged != null) { AuthorChanged(this, new AnnotationAuthorChangedEventArgs(this, action, author)); } } ////// Fires a ResourceChanged event for the given resource and action. /// /// the resource to notify about /// the action that took place for that resource /// the handlers to notify private void FireResourceEvent(AnnotationResource resource, AnnotationAction action, AnnotationResourceChangedEventHandler handlers) { // resource can be null - we allow that because it could be added or removed from the annotation. Invariant.Assert(action >= AnnotationAction.Added && action <= AnnotationAction.Modified, "Unknown AnnotationAction"); // Always update the modification time before firing change events _modified = DateTime.Now; if (handlers != null) { handlers(this, new AnnotationResourceChangedEventArgs(this, action, resource)); } } private void Init() { _cargos = new AnnotationResourceCollection(); _cargos.ItemChanged += OnCargoChanged; _cargos.CollectionChanged += OnCargosChanged; _anchors = new AnnotationResourceCollection(); _anchors.ItemChanged += OnAnchorChanged; _anchors.CollectionChanged += OnAnchorsChanged; _authors = new ObservableCollection(); _authors.CollectionChanged += OnAuthorsChanged; } #endregion Private Methods //------------------------------------------------------ // // Private Fields // //----------------------------------------------------- #region Private Fields /// /// This annotation's unique indentifier /// private Guid _id; ////// Type name of this annotation /// private XmlQualifiedName _typeName; ////// Time of creation of this annotation (set by the store) /// private DateTime _created; ////// Time of last update to this annotatin (set by the store) /// private DateTime _modified; ////// The authors for this annotation - zero or more authors /// private ObservableCollection_authors; /// /// The cargo for this annotation - nothing or a single resource /// private AnnotationResourceCollection _cargos; ////// The contexts for this annotation - zero or more resources /// private AnnotationResourceCollection _anchors; ////// Serializer for resources - used to serialize and deserialize annotations /// private static Serializer _ResourceSerializer; ////// Colon used to split the parts of a qualified name attribute value /// private static readonly char[] _Colon = new char[] { ':' }; #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // Annotation class is the top-level Object Model class for the // annotation framework. It represents a single annotation with // all of its anchoring and content data. // // Spec: http://team/sites/ag/Specifications/Simplifying%20Store%20Cache%20Model.doc // // History: // 10/04/2002: rruiz: Added header comment to ObjectModel.cs // 07/03/2003: magedz: Renamed Link, LinkSequence to LocatorPart and Locator // respectively. // 05/31/2003: LGolding: Ported to WCP tree. // 07/15/2003: rruiz: Rewrote implementations to extend abstract classes // instead of implement interfaces; got rid of obsolete // classes; put each class in separate file. // 12/03/2003: ssimova: Changed Contexts to Anchors // 6/30/2004: rruiz: Made the class concrete, changed the APIs to be more // typesafe, made the class XML serializable. // //----------------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Windows.Annotations.Storage; using System.Windows.Data; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; using MS.Internal; using MS.Internal.Annotations; using MS.Utility; namespace System.Windows.Annotations { ////// Actions that can be taken on subparts of an /// Annotation - authors, anchors, and cargos. /// public enum AnnotationAction { ////// The subpart was added to the Annotation. /// Added, ////// The subpart was removed from the Annotation. /// Removed, ////// The subpart already is part of the Annotation and was modified. /// Modified } ////// Annotation class is the top-level Object Model class for the /// annotation framework. It represents a single annotation with /// all of its anchoring and content data. /// [XmlRoot(Namespace = AnnotationXmlConstants.Namespaces.CoreSchemaNamespace, ElementName = AnnotationXmlConstants.Elements.Annotation)] public sealed class Annotation : IXmlSerializable { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors ////// Creates an instance of Annotation for use by XML serialization. /// This constructor should not be used directly. It does not /// initialize the instance. /// public Annotation() { // Should only be used from XML serialization. This instance will // not be a valid Annotation if used outside of serialization. _id = Guid.Empty; _created = DateTime.MinValue; _modified = DateTime.MinValue; Init(); } ////// Creates an instance of Annotation with the specified type name. /// /// fully qualified type name of the new Annotation ///annotationType is null ///annotationType's Name or Namespace is null or empty string public Annotation(XmlQualifiedName annotationType) { if (annotationType == null) { throw new ArgumentNullException("annotationType"); } if (String.IsNullOrEmpty(annotationType.Name)) { throw new ArgumentException(SR.Get(SRID.TypeNameMustBeSpecified), "annotationType.Name");//todo better message } if (String.IsNullOrEmpty(annotationType.Namespace)) { throw new ArgumentException(SR.Get(SRID.TypeNameMustBeSpecified), "annotationType.Namespace");//todo better message } _id = Guid.NewGuid(); _typeName = annotationType; // For an new instance of Annotation, _created should be == with _modified _created = DateTime.Now; _modified = _created; Init(); } ////// Creates an instance of Annotation with the values provided. This /// constructor is for use by stores using their own serialization method. /// It provides a way to create an annotation with all the necessary /// read-only data. /// /// the fully qualified type name of the new Annotation /// the id of the new Annotation /// the time the annotation was first created /// the time the annotation was last modified ///annotationType is null ///lastModificationTime is earlier than creationTime ///annotationType's Name or Namespace is null or empty string ///id is equal to Guid.Empty public Annotation(XmlQualifiedName annotationType, Guid id, DateTime creationTime, DateTime lastModificationTime) { if (annotationType == null) { throw new ArgumentNullException("annotationType"); } if (String.IsNullOrEmpty(annotationType.Name)) { throw new ArgumentException(SR.Get(SRID.TypeNameMustBeSpecified), "annotationType.Name");//todo better message } if (String.IsNullOrEmpty(annotationType.Namespace)) { throw new ArgumentException(SR.Get(SRID.TypeNameMustBeSpecified), "annotationType.Namespace");//todo better message } if (id.Equals(Guid.Empty)) { throw new ArgumentException(SR.Get(SRID.InvalidGuid), "id"); } if (lastModificationTime.CompareTo(creationTime) < 0) { throw new ArgumentException(SR.Get(SRID.ModificationEarlierThanCreation), "lastModificationTime"); } _id = id; _typeName = annotationType; _created = creationTime; _modified = lastModificationTime; Init(); } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods #region IXmlSerializable Implementation ////// Returns null. The annotations schema is available at /// http://schemas.microsoft.com/windows/annotations/2003/11/core. /// public XmlSchema GetSchema() { return null; } ////// Serializes this Annotation to XML with the passed in XmlWriter. /// /// the writer to serialize the Annotation to ///writer is null public void WriteXml(XmlWriter writer) { if (writer == null) { throw new ArgumentNullException("writer"); } //fire trace event EventTrace.NormalTraceEvent(EventTraceGuidId.SERIALIZEANNOTATIONGUID, EventType.StartEvent); if (String.IsNullOrEmpty(writer.LookupPrefix(AnnotationXmlConstants.Namespaces.CoreSchemaNamespace))) { writer.WriteAttributeString(AnnotationXmlConstants.Prefixes.XmlnsPrefix, AnnotationXmlConstants.Prefixes.CoreSchemaPrefix, null, AnnotationXmlConstants.Namespaces.CoreSchemaNamespace); } if (String.IsNullOrEmpty(writer.LookupPrefix(AnnotationXmlConstants.Namespaces.BaseSchemaNamespace))) { writer.WriteAttributeString(AnnotationXmlConstants.Prefixes.XmlnsPrefix, AnnotationXmlConstants.Prefixes.BaseSchemaPrefix, null, AnnotationXmlConstants.Namespaces.BaseSchemaNamespace); } if (_typeName == null) { throw new InvalidOperationException(SR.Get(SRID.CannotSerializeInvalidInstance)); } // XmlConvert.ToString is [Obsolete] #pragma warning disable 0618 writer.WriteAttributeString(AnnotationXmlConstants.Attributes.Id, XmlConvert.ToString(_id)); writer.WriteAttributeString(AnnotationXmlConstants.Attributes.CreationTime, XmlConvert.ToString(_created)); writer.WriteAttributeString(AnnotationXmlConstants.Attributes.LastModificationTime, XmlConvert.ToString(_modified)); #pragma warning restore 0618 writer.WriteStartAttribute(AnnotationXmlConstants.Attributes.TypeName); writer.WriteQualifiedName(_typeName.Name, _typeName.Namespace); writer.WriteEndAttribute(); if (_authors != null && _authors.Count > 0) { writer.WriteStartElement(AnnotationXmlConstants.Elements.AuthorCollection, AnnotationXmlConstants.Namespaces.CoreSchemaNamespace); foreach (string author in _authors) { if (author != null) { writer.WriteElementString(AnnotationXmlConstants.Prefixes.BaseSchemaPrefix, AnnotationXmlConstants.Elements.StringAuthor, AnnotationXmlConstants.Namespaces.BaseSchemaNamespace, author); } } writer.WriteEndElement(); } if (_anchors != null && _anchors.Count > 0) { writer.WriteStartElement(AnnotationXmlConstants.Elements.AnchorCollection, AnnotationXmlConstants.Namespaces.CoreSchemaNamespace); foreach (AnnotationResource anchor in _anchors) { if (anchor != null) { ResourceSerializer.Serialize(writer, anchor); } } writer.WriteEndElement(); } if (_cargos != null && _cargos.Count > 0) { writer.WriteStartElement(AnnotationXmlConstants.Elements.CargoCollection, AnnotationXmlConstants.Namespaces.CoreSchemaNamespace); foreach (AnnotationResource cargo in _cargos) { if (cargo != null) { ResourceSerializer.Serialize(writer, cargo); } } writer.WriteEndElement(); } //fire trace event EventTrace.NormalTraceEvent(EventTraceGuidId.SERIALIZEANNOTATIONGUID, EventType.EndEvent); } ////// Deserializes an Annotation from the XmlReader passed in. /// /// reader to deserialize from ///reader is null public void ReadXml(XmlReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } //fire trace event EventTrace.NormalTraceEvent(EventTraceGuidId.DESERIALIZEANNOTATIONGUID, EventType.StartEvent); XmlDocument doc = new XmlDocument(); ReadAttributes(reader); if (!reader.IsEmptyElement) { reader.Read(); // Read the remainder of the "Annotation" start tag while (!(XmlNodeType.EndElement == reader.NodeType && AnnotationXmlConstants.Elements.Annotation == reader.LocalName)) { if (AnnotationXmlConstants.Elements.AnchorCollection == reader.LocalName) { CheckForNonNamespaceAttribute(reader, AnnotationXmlConstants.Elements.AnchorCollection); if (!reader.IsEmptyElement) { reader.Read(); // Reads the "Anchors" start tag while (!(AnnotationXmlConstants.Elements.AnchorCollection == reader.LocalName && XmlNodeType.EndElement == reader.NodeType)) { AnnotationResource anchor = (AnnotationResource)ResourceSerializer.Deserialize(reader); _anchors.Add(anchor); } } reader.Read(); // Reads the "Anchors" end tag (or whole tag if it was empty) } else if (AnnotationXmlConstants.Elements.CargoCollection == reader.LocalName) { CheckForNonNamespaceAttribute(reader, AnnotationXmlConstants.Elements.CargoCollection); if (!reader.IsEmptyElement) { reader.Read(); // Reads the "Cargos" start tag while (!(AnnotationXmlConstants.Elements.CargoCollection == reader.LocalName && XmlNodeType.EndElement == reader.NodeType)) { AnnotationResource cargo = (AnnotationResource)ResourceSerializer.Deserialize(reader); _cargos.Add(cargo); } } reader.Read(); // Reads the "Cargos" end tag (or whole tag if it was empty) } else if (AnnotationXmlConstants.Elements.AuthorCollection == reader.LocalName) { CheckForNonNamespaceAttribute(reader, AnnotationXmlConstants.Elements.AuthorCollection); if (!reader.IsEmptyElement) { reader.Read(); // Reads the "Authors" start tag while (!(AnnotationXmlConstants.Elements.AuthorCollection == reader.LocalName && XmlNodeType.EndElement == reader.NodeType)) { if (!(AnnotationXmlConstants.Elements.StringAuthor == reader.LocalName && XmlNodeType.Element == reader.NodeType)) { throw new XmlException(SR.Get(SRID.InvalidXmlContent, AnnotationXmlConstants.Elements.Annotation)); } XmlNode node = doc.ReadNode(reader); // Reads the entire "StringAuthor" tag if (!reader.IsEmptyElement) { _authors.Add(node.InnerText); } } } reader.Read(); // Reads the "Authors" end tag (or whole tag if it was empty) } else { // The annotation must contain some invalid content which is not part of the schema. throw new XmlException(SR.Get(SRID.InvalidXmlContent, AnnotationXmlConstants.Elements.Annotation)); } } } reader.Read(); // Read the end of the "Annotation" tag (or the whole tag if its empty) //fire trace event EventTrace.NormalTraceEvent(EventTraceGuidId.DESERIALIZEANNOTATIONGUID, EventType.EndEvent); } #endregion IXmlSerializable Implementation #endregion Public Methods //------------------------------------------------------ // // Public Operators // //------------------------------------------------------ //----------------------------------------------------- // // Public Events // //------------------------------------------------------ #region Public Events ////// Event fired when an author is added, removed or modified in anyway. /// public event AnnotationAuthorChangedEventHandler AuthorChanged; ////// Event fired when an anchor is added, removed or modified in anyway. /// This includes modifications to an anchor's sub-parts such as /// changing a value on a ContentLocatorPart which is contained by a ContentLocatorBase /// which is contained by an anchor which is contained by this /// Annotation. /// public event AnnotationResourceChangedEventHandler AnchorChanged; ////// Event fired when an cargo is added, removed or modified in anyway. /// This includes modifications to a cargo's sub-parts such as /// changing an attribute on an XmlNode contained by a content which /// is contained by a cargo which is contained by this Annotation. /// public event AnnotationResourceChangedEventHandler CargoChanged; #endregion Public Events //----------------------------------------------------- // // Public Properties // //----------------------------------------------------- #region Public Properties ////// An Annotation is given a unique Guid when it is first instantiated. /// ///the unique id of this Annotation; this property will return /// Guid.Empty if the Annotation was instantied with the default constructor - /// which should not be used directly public Guid Id { get { return _id; } } ////// The type of this Annotation. /// ///the type of this Annotation; this property will only return /// null if the Annotation was instantiated with the default constructor - which /// should not be used directly public XmlQualifiedName AnnotationType { get { return _typeName; } } ////// The time of creation for this Annotation. This is set when /// the Annotation is first instantiated. /// ///the creation time of this Annotation; this property will return /// DateTime.MinValue if the Annotation was instantiated with the default constructor - /// which should not be used directly public DateTime CreationTime { get { return _created; } } ////// The time of the Annotation was last modified. This is set after any /// change to Annotation before any notifications are fired. /// ///the last modification time of this Annotation; this property will /// return DateTime.MinValue if the Annotation was instantiated with the default /// constructor - which should not be used directly public DateTime LastModificationTime { get { return _modified; } } ////// The collection of zero or more authors for this Annotation. /// ///collection of authors for this Annotation; never returns null public CollectionAuthors { get { return _authors; } } /// /// The collection of zero or more Resources that represent the anchors /// of this Annotation. These could be references to content, /// actually include the content itself, or both (as in the case of /// a snippet being the anchor of a comment). /// ///collection of Resources; never returns null public CollectionAnchors { get { return _anchors; } } /// /// The collection of zero or more Resources that represent the cargos /// of this Annotation. These could be references to content, /// actually include the content itself, or both (as in the case of /// a snippet from a web-page being the cargo). /// ///collection of Resources; never returns null public CollectionCargos { get { return _cargos; } } #endregion Public Properties //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ #region Internal Methods /// /// Returns true if the reader is positioned on an attribute that /// is a namespace attribute - for instance xmlns="xx", xmlns:bac="http:bac", /// or xml:lang="en-us". /// internal static bool IsNamespaceDeclaration(XmlReader reader) { Invariant.Assert(reader != null); // The reader is on a namespace declaration if: // - the current node is an attribute AND either // - the attribute has no prefix and local name is 'xmlns' // - the attribute's prefix is 'xmlns' or 'xml' if (reader.NodeType == XmlNodeType.Attribute) { if (reader.Prefix.Length == 0) { if (reader.LocalName == AnnotationXmlConstants.Prefixes.XmlnsPrefix) return true; } else { if (reader.Prefix == AnnotationXmlConstants.Prefixes.XmlnsPrefix || reader.Prefix == AnnotationXmlConstants.Prefixes.XmlPrefix) return true; } } return false; } ////// Checks all attributes for the current node. If any attribute isn't a /// namespace attribute an exception is thrown. /// internal static void CheckForNonNamespaceAttribute(XmlReader reader, string elementName) { Invariant.Assert(reader != null, "No reader supplied."); Invariant.Assert(elementName != null, "No element name supplied."); while (reader.MoveToNextAttribute()) { // If the attribute is a namespace declaration we should ignore it if (Annotation.IsNamespaceDeclaration(reader)) { continue; } throw new XmlException(SR.Get(SRID.UnexpectedAttribute, reader.LocalName, elementName)); } // We need to move the reader back to the original element the // attributes are on for the next reader operation. Has no effect // if no attributes were looked at reader.MoveToContent(); } #endregion Internal Methods //----------------------------------------------------- // // Private Properties // //------------------------------------------------------ #region Private Properties ////// Returns serializer for Resource objects. Lazily creates /// the serializer for cases where its not needed. /// private static Serializer ResourceSerializer { get { if (_ResourceSerializer == null) { _ResourceSerializer = new Serializer(typeof(AnnotationResource)); } return _ResourceSerializer; } } #endregion Private Properties //------------------------------------------------------ // // Private Methods // //----------------------------------------------------- #region Private Methods private void ReadAttributes(XmlReader reader) { Invariant.Assert(reader != null, "No reader passed in."); // Read all the attributes while (reader.MoveToNextAttribute()) { string value = reader.Value; // Skip null and empty values - they will be treated the // same as if they weren't specified at all if (String.IsNullOrEmpty(value)) continue; switch (reader.LocalName) { case AnnotationXmlConstants.Attributes.Id: _id = XmlConvert.ToGuid(value); break; // XmlConvert.ToDateTime is [Obsolete] #pragma warning disable 0618 case AnnotationXmlConstants.Attributes.CreationTime: _created = XmlConvert.ToDateTime(value); break; case AnnotationXmlConstants.Attributes.LastModificationTime: _modified = XmlConvert.ToDateTime(value); break; #pragma warning restore 0618 case AnnotationXmlConstants.Attributes.TypeName: string[] typeName = value.Split(_Colon); if (typeName.Length == 1) { typeName[0] = typeName[0].Trim(); if (String.IsNullOrEmpty(typeName[0])) { // Just a string of whitespace (empty string doesn't get processed) throw new FormatException(SR.Get(SRID.InvalidAttributeValue, AnnotationXmlConstants.Attributes.TypeName)); } _typeName = new XmlQualifiedName(typeName[0]); } else if (typeName.Length == 2) { typeName[0] = typeName[0].Trim(); typeName[1] = typeName[1].Trim(); if (String.IsNullOrEmpty(typeName[0]) || String.IsNullOrEmpty(typeName[1])) { // One colon, prefix or suffix is empty string or whitespace throw new FormatException(SR.Get(SRID.InvalidAttributeValue, AnnotationXmlConstants.Attributes.TypeName)); } _typeName = new XmlQualifiedName(typeName[1], reader.LookupNamespace(typeName[0])); } else { // More than one colon throw new FormatException(SR.Get(SRID.InvalidAttributeValue, AnnotationXmlConstants.Attributes.TypeName)); } break; default: if (!Annotation.IsNamespaceDeclaration(reader)) throw new XmlException(SR.Get(SRID.UnexpectedAttribute, reader.LocalName, AnnotationXmlConstants.Elements.Annotation)); break; } } // Test to see if any required attribute was missing if (_id.Equals(Guid.Empty)) { throw new XmlException(SR.Get(SRID.RequiredAttributeMissing, AnnotationXmlConstants.Attributes.Id, AnnotationXmlConstants.Elements.Annotation)); } if (_created.Equals(DateTime.MinValue)) { throw new XmlException(SR.Get(SRID.RequiredAttributeMissing, AnnotationXmlConstants.Attributes.CreationTime, AnnotationXmlConstants.Elements.Annotation)); } if (_modified.Equals(DateTime.MinValue)) { throw new XmlException(SR.Get(SRID.RequiredAttributeMissing, AnnotationXmlConstants.Attributes.LastModificationTime, AnnotationXmlConstants.Elements.Annotation)); } if (_typeName == null) { throw new XmlException(SR.Get(SRID.RequiredAttributeMissing, AnnotationXmlConstants.Attributes.TypeName, AnnotationXmlConstants.Elements.Annotation)); } // Move back to the parent "Annotation" element reader.MoveToContent(); } private void OnCargoChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { FireResourceEvent((AnnotationResource)sender, AnnotationAction.Modified, CargoChanged); } private void OnCargosChanged(object sender, NotifyCollectionChangedEventArgs e) { AnnotationAction action = AnnotationAction.Added; IList changedItems = null; switch (e.Action) { case NotifyCollectionChangedAction.Add: action = AnnotationAction.Added; changedItems = e.NewItems; break; case NotifyCollectionChangedAction.Remove: action = AnnotationAction.Removed; changedItems = e.OldItems; break; case NotifyCollectionChangedAction.Replace: // For Replace we need to fire removes and adds. As in other // event firing code - if a listener for one event throws the // rest of the events won't be fired. foreach (AnnotationResource cargo in e.OldItems) { FireResourceEvent(cargo, AnnotationAction.Removed, CargoChanged); } changedItems = e.NewItems; break; case NotifyCollectionChangedAction.Move: // ignore - this only happens on sort break; case NotifyCollectionChangedAction.Reset: // ignore - this only happens on sort break; default: throw new NotSupportedException(SR.Get(SRID.UnexpectedCollectionChangeAction, e.Action)); } if (changedItems != null) { foreach (AnnotationResource cargo in changedItems) { FireResourceEvent(cargo, action, CargoChanged); } } } private void OnAnchorChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { FireResourceEvent((AnnotationResource)sender, AnnotationAction.Modified, AnchorChanged); } private void OnAnchorsChanged(object sender, NotifyCollectionChangedEventArgs e) { AnnotationAction action = AnnotationAction.Added; IList changedItems = null; switch (e.Action) { case NotifyCollectionChangedAction.Add: action = AnnotationAction.Added; changedItems = e.NewItems; break; case NotifyCollectionChangedAction.Remove: action = AnnotationAction.Removed; changedItems = e.OldItems; break; case NotifyCollectionChangedAction.Replace: // For Replace we need to fire removes and adds. As in other // event firing code - if a listener for one event throws the // rest of the events won't be fired. foreach (AnnotationResource anchor in e.OldItems) { FireResourceEvent(anchor, AnnotationAction.Removed, AnchorChanged); } changedItems = e.NewItems; break; case NotifyCollectionChangedAction.Move: // ignore - this only happens on sort break; case NotifyCollectionChangedAction.Reset: // ignore - this only happens on sort break; default: throw new NotSupportedException(SR.Get(SRID.UnexpectedCollectionChangeAction, e.Action)); } if (changedItems != null) { foreach (AnnotationResource anchor in changedItems) { FireResourceEvent(anchor, action, AnchorChanged); } } } private void OnAuthorsChanged(object sender, NotifyCollectionChangedEventArgs e) { AnnotationAction action = AnnotationAction.Added; IList changedItems = null; switch (e.Action) { case NotifyCollectionChangedAction.Add: action = AnnotationAction.Added; changedItems = e.NewItems; break; case NotifyCollectionChangedAction.Remove: action = AnnotationAction.Removed; changedItems = e.OldItems; break; case NotifyCollectionChangedAction.Replace: // For Replace we need to fire removes and adds. As in other // event firing code - if a listener for one event throws the // rest of the events won't be fired. foreach (string author in e.OldItems) { FireAuthorEvent(author, AnnotationAction.Removed); } changedItems = e.NewItems; break; case NotifyCollectionChangedAction.Move: // ignore - this only happens on sort break; case NotifyCollectionChangedAction.Reset: // ignore - this only happens on sort break; default: throw new NotSupportedException(SR.Get(SRID.UnexpectedCollectionChangeAction, e.Action)); } if (changedItems != null) { foreach (Object author in changedItems) { FireAuthorEvent(author, action); } } } ////// Fires an AuthorChanged event for the given author and action. /// /// the author to notify about /// the action that took place for that author private void FireAuthorEvent(Object author, AnnotationAction action) { // 'author' can be null because null authors are allowed in the collection Invariant.Assert(action >= AnnotationAction.Added && action <= AnnotationAction.Modified, "Unknown AnnotationAction"); // Always update the modification time before firing change events _modified = DateTime.Now; if (AuthorChanged != null) { AuthorChanged(this, new AnnotationAuthorChangedEventArgs(this, action, author)); } } ////// Fires a ResourceChanged event for the given resource and action. /// /// the resource to notify about /// the action that took place for that resource /// the handlers to notify private void FireResourceEvent(AnnotationResource resource, AnnotationAction action, AnnotationResourceChangedEventHandler handlers) { // resource can be null - we allow that because it could be added or removed from the annotation. Invariant.Assert(action >= AnnotationAction.Added && action <= AnnotationAction.Modified, "Unknown AnnotationAction"); // Always update the modification time before firing change events _modified = DateTime.Now; if (handlers != null) { handlers(this, new AnnotationResourceChangedEventArgs(this, action, resource)); } } private void Init() { _cargos = new AnnotationResourceCollection(); _cargos.ItemChanged += OnCargoChanged; _cargos.CollectionChanged += OnCargosChanged; _anchors = new AnnotationResourceCollection(); _anchors.ItemChanged += OnAnchorChanged; _anchors.CollectionChanged += OnAnchorsChanged; _authors = new ObservableCollection(); _authors.CollectionChanged += OnAuthorsChanged; } #endregion Private Methods //------------------------------------------------------ // // Private Fields // //----------------------------------------------------- #region Private Fields /// /// This annotation's unique indentifier /// private Guid _id; ////// Type name of this annotation /// private XmlQualifiedName _typeName; ////// Time of creation of this annotation (set by the store) /// private DateTime _created; ////// Time of last update to this annotatin (set by the store) /// private DateTime _modified; ////// The authors for this annotation - zero or more authors /// private ObservableCollection_authors; /// /// The cargo for this annotation - nothing or a single resource /// private AnnotationResourceCollection _cargos; ////// The contexts for this annotation - zero or more resources /// private AnnotationResourceCollection _anchors; ////// Serializer for resources - used to serialize and deserialize annotations /// private static Serializer _ResourceSerializer; ////// Colon used to split the parts of a qualified name attribute value /// private static readonly char[] _Colon = new char[] { ':' }; #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Codec.cs
- ImageBrush.cs
- XmlDataLoader.cs
- ExpressionLexer.cs
- PriorityItem.cs
- Stroke.cs
- SoapFault.cs
- MessageBox.cs
- ByeOperation11AsyncResult.cs
- PeerConnector.cs
- XmlConvert.cs
- ECDiffieHellmanCngPublicKey.cs
- DPTypeDescriptorContext.cs
- ObjectStateEntry.cs
- NestedContainer.cs
- TypeReference.cs
- DateTimePickerDesigner.cs
- ScriptManager.cs
- GrammarBuilder.cs
- WorkflowServiceAttributes.cs
- ButtonChrome.cs
- ObjectItemAttributeAssemblyLoader.cs
- Cursors.cs
- DesignSurfaceCollection.cs
- AppSettingsReader.cs
- ResourcePermissionBaseEntry.cs
- ReferencedType.cs
- DateTimeStorage.cs
- TagMapInfo.cs
- WebPartChrome.cs
- WindowExtensionMethods.cs
- ObfuscateAssemblyAttribute.cs
- OwnerDrawPropertyBag.cs
- OperandQuery.cs
- WorkerProcess.cs
- SchemaObjectWriter.cs
- GroupQuery.cs
- SafeNativeMethods.cs
- ScriptServiceAttribute.cs
- MergePropertyDescriptor.cs
- TimeSpanValidator.cs
- ValueTable.cs
- NotImplementedException.cs
- TransformGroup.cs
- XmlSchemaAnnotation.cs
- ColorContext.cs
- DiscoveryClientChannelFactory.cs
- CreateUserErrorEventArgs.cs
- Sql8ConformanceChecker.cs
- CodeExpressionRuleDeclaration.cs
- Exception.cs
- RecordManager.cs
- NativeStructs.cs
- AudioException.cs
- Point.cs
- FormViewDeleteEventArgs.cs
- AtomicFile.cs
- ForwardPositionQuery.cs
- JournalNavigationScope.cs
- Emitter.cs
- HasRunnableWorkflowEvent.cs
- Content.cs
- HMACSHA384.cs
- FixedTextBuilder.cs
- XmlLinkedNode.cs
- RuntimeResourceSet.cs
- StrokeCollectionDefaultValueFactory.cs
- IdnMapping.cs
- TypeInitializationException.cs
- initElementDictionary.cs
- DrawingCollection.cs
- LinqToSqlWrapper.cs
- ButtonColumn.cs
- glyphs.cs
- StringSource.cs
- Part.cs
- hresults.cs
- TraceSwitch.cs
- DmlSqlGenerator.cs
- AnimationException.cs
- XpsFilter.cs
- DesignerVerbCollection.cs
- XsltFunctions.cs
- LinkDescriptor.cs
- Style.cs
- SafeMemoryMappedFileHandle.cs
- Win32SafeHandles.cs
- SqlProviderManifest.cs
- RoleGroupCollection.cs
- DataSourceGroupCollection.cs
- PageCodeDomTreeGenerator.cs
- Cursors.cs
- CounterSample.cs
- XmlSchemaCompilationSettings.cs
- ViewBase.cs
- VirtualPath.cs
- MatrixCamera.cs
- Directory.cs
- SrgsRuleRef.cs
- BlockUIContainer.cs