/// <summary> /// Removes the first instance of an element that has the given name. /// </summary> /// <param name="name">The name of the element to remove.</param> /// <returns>Returns true if the element was successfully removed. False if it did not exist within this template.</returns> public bool RemoveElementByName(string name) { if (_Children == null || _Children.Count < 1 || name == null || name.Length < 1) { return(false); } BaseElement elm = null; foreach (BaseElement element in _Children) { if (element.Name == name) { elm = element; } } if (elm != null) { bool result = RemoveElement(elm); elm.Parent = null; return(result); } return(false); }
/// <summary> /// This method performs reconciliation on all existing elements so that the old /// template matches this one. /// Then it adds new elements to the old template. Finally, it tries to reconcile /// elements that have been fundamentally changed in the new template. Failing that, /// elements that cannot be resolved are simply removed until the old template /// matches the new one. /// </summary> /// <param name="oldTemplate"></param> /// <returns></returns> public bool ReconcileElementProperties(BaseElement oldTemplate) { if (!this.Guid.Equals(oldTemplate.Guid)) { return(false); } Type sourceType = this.GetType(); Type oldType = this.GetType(); //first, let's do the easy stuff and update existing properties for both templates foreach (var property in sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { var targetProperty = oldType.GetProperty(property.Name, BindingFlags.Public | BindingFlags.Instance); if (targetProperty != null && targetProperty.CanWrite && targetProperty.GetCustomAttribute <ReconcilableProp>(true) != null && property.GetCustomAttribute <ShallowElementCloneAttribute>(true) != null) { targetProperty.SetValue(oldTemplate, property.GetValue(this, null), null); } } List <IElement> newElements = new List <IElement>(); //now we are going to loop through the list of elements within the template //and try to reconcile their properties. foreach (IElement element in _Children) { bool notCopied = true; //yucky inner-loop that loop that looks //for the matching element within the old template. foreach (BaseElement oldElement in oldTemplate.Children) { //this automatically checks the Guids to see if //they are the matching element. No worries here. //It will simply return if there is not a match... //or you know... they generated the same Guid somehow ;) if (element.ReconcileElementProperties(oldElement)) { notCopied = false; break; } } //if the element couldn't be found in the old template, we'll need to //add it to a list that will be appened later if (notCopied) { newElements.Add(element); } } //now something tricky. We need to add elements to //the old template to match the new one. foreach (IElement append in newElements) { oldTemplate.AddElement(append.GetShallowClone()); } return(false); }
/// <summary> /// Copies this element to another element using shallow copying /// of all basic properties. Child elements however, are still /// deeply copied using recursion. This will not handle indexed properties. /// </summary> /// <returns></returns> public BaseElement GetShallowClone() { BaseElement dest = Activator.CreateInstance(this.GetType()) as BaseElement; if (dest == null) { return(null); } Type sourceType = this.GetType(); Type targetType = dest.GetType(); //copy all values of all elements marked with a clone attribute foreach (var property in sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { var targetProperty = targetType.GetProperty(property.Name, BindingFlags.Public | BindingFlags.Instance); if (targetProperty != null && targetProperty.CanWrite && targetProperty.PropertyType.IsAssignableFrom(property.PropertyType) && targetProperty.GetCustomAttribute <ShallowElementCloneAttribute>(true) != null && property.GetCustomAttribute <ShallowElementCloneAttribute>(true) != null) { targetProperty.SetValue(dest, property.GetValue(this, null), null); } else if (targetProperty != null && targetProperty.CanWrite && targetProperty.PropertyType.IsAssignableFrom(property.PropertyType) && targetProperty.GetCustomAttribute <DeepElementCloneAttribute>(true) != null && property.GetCustomAttribute <DeepElementCloneAttribute>(true) != null) { try { targetProperty.SetValue(dest, Utils.ObjectHelper.Clone(property.GetValue(this, null)), null); } catch (ArgumentException e) { MessageBox.Show("Failed to deep copy the property '" + property.Name + "' of the element '" + this._Name + "'.\n" + e.Message); } } else if ( targetProperty != null && targetProperty.CanWrite && targetProperty.PropertyType.IsAssignableFrom(property.PropertyType) && targetProperty.GetCustomAttribute <ContentElementCloneAttribute>(true) != null && property.GetCustomAttribute <ContentElementCloneAttribute>(true) != null) { this.DeepClone(property, this, targetProperty, dest); } } //manually copy InstanceProperties //We need to generate the InstanceEditProperty controls and bind them here. dest.BindInstanceEditProps(); //TODO: set default values to binding property //now deep shallow-copy of the children foreach (BaseElement child in _Children) { dest.Children.Add(child.GetShallowClone()); } //we use reflection to get the private Guid value. //We do this in an effort to avoid letting overriding //classes mess with the Guid FieldInfo sourceGuid = sourceType.GetField("_Guid", BindingFlags.NonPublic | BindingFlags.Instance); FieldInfo destGuid = targetType.GetField("_Guid", BindingFlags.NonPublic | BindingFlags.Instance); destGuid.SetValue(dest, sourceGuid.GetValue(this)); return(dest); }
/// <summary> /// Adds a new element to the template. /// </summary> /// <param name="element"></param> public virtual void AddElement(BaseElement element) { InitElementList(); _Children.Add(ConvertElement(element)); element.Parent = this; }
/// <summary> /// This default implementation in fact does not peform a deep copy. It is a stand-in /// shallow copy using reflection of the object's proeprties. For a proper deep-copy, /// override this method and implement according to the Element's _Content datatype. /// </summary> /// <param name="sourceProp"></param> /// <param name="sourceElm"></param> /// <param name="destProp"></param> /// <param name="destElm"></param> protected virtual void DeepClone(PropertyInfo sourceProp, BaseElement sourceElm, PropertyInfo destProp, BaseElement destElm) { destProp.SetValue(destElm, sourceProp.GetValue(sourceElm, null), null); }