using System; using System.Collections.Specialized; using System.Diagnostics; using System.Runtime.Serialization; using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Models { /// /// A group of property types, which corresponds to the properties grouped under a Tab. /// [Serializable] [DataContract(IsReference = true)] [DebuggerDisplay("Id: {Id}, Name: {Name}")] public class PropertyGroup : EntityBase, IEquatable { private string _name; private int _sortOrder; private PropertyTypeCollection _propertyTypes; public PropertyGroup(bool isPublishing) : this(new PropertyTypeCollection(isPublishing)) { } public PropertyGroup(PropertyTypeCollection propertyTypeCollection) { PropertyTypes = propertyTypeCollection; } private void PropertyTypesChanged(object sender, NotifyCollectionChangedEventArgs e) { OnPropertyChanged(nameof(PropertyTypes)); } /// /// Gets or sets the Name of the Group, which corresponds to the Tab-name in the UI /// [DataMember] public string Name { get => _name; set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } /// /// Gets or sets the Sort Order of the Group /// [DataMember] public int SortOrder { get => _sortOrder; set => SetPropertyValueAndDetectChanges(value, ref _sortOrder, nameof(SortOrder)); } /// /// Gets or sets a collection of PropertyTypes for this PropertyGroup /// /// /// Marked DoNotClone because we will manually deal with cloning and the event handlers /// [DataMember] [DoNotClone] public PropertyTypeCollection PropertyTypes { get => _propertyTypes; set { if (_propertyTypes != null) { _propertyTypes.ClearCollectionChangedEvents(); } _propertyTypes = value; // since we're adding this collection to this group, // we need to ensure that all the lazy values are set. foreach (var propertyType in _propertyTypes) propertyType.PropertyGroupId = new Lazy(() => Id); OnPropertyChanged(nameof(PropertyTypes)); _propertyTypes.CollectionChanged += PropertyTypesChanged; } } public bool Equals(PropertyGroup other) { if (base.Equals(other)) return true; return other != null && Name.InvariantEquals(other.Name); } public override int GetHashCode() { var baseHash = base.GetHashCode(); var nameHash = Name.ToLowerInvariant().GetHashCode(); return baseHash ^ nameHash; } protected override void PerformDeepClone(object clone) { base.PerformDeepClone(clone); var clonedEntity = (PropertyGroup)clone; if (clonedEntity._propertyTypes != null) { clonedEntity._propertyTypes.ClearCollectionChangedEvents(); //clear this event handler if any clonedEntity._propertyTypes = (PropertyTypeCollection) _propertyTypes.DeepClone(); //manually deep clone clonedEntity._propertyTypes.CollectionChanged += clonedEntity.PropertyTypesChanged; //re-assign correct event handler } } } }