/// <summary> /// When a complex property on this instance changes, this method performs /// the necessary attach/detach operations for the new instance. /// </summary> /// <param name="metaMember">The complex member.</param> private void AttachComplexObjectInstance(MetaMember metaMember) { // First check if the parent has an existing instance attached for this // property and detach if necessary. string memberName = metaMember.Member.Name; ComplexObject prevInstance = null; if (this.TrackedInstances.TryGetValue(memberName, out prevInstance)) { prevInstance.Detach(); this.TrackedInstances.Remove(memberName); } ComplexObject newInstance = (ComplexObject)metaMember.GetValue(this); if (newInstance != null) { // Attach to the new instance newInstance.Attach(this, memberName, this.OnDataMemberChanging, this.OnDataMemberChanged, this.OnMemberValidationChanged); this.TrackedInstances[memberName] = newInstance; // If the instance has validation errors, we need to sync them into our parent. This // needs to be done as a merge operation, since the parent may already have property // level errors for this member that must be retained. if (newInstance.HasValidationErrors) { foreach (ValidationResult error in ValidationUtilities.ApplyMemberPath(newInstance.ValidationErrors, memberName)) { this.ValidationResultCollection.Add(error); } } } }
/// <summary> /// Validate the changeset. /// </summary> /// <param name="validationContext">The ValidationContext to use.</param> /// <returns>True if the changeset is valid, false otherwise.</returns> internal bool Validate(ValidationContext validationContext) { bool success = true; foreach (Entity entity in this) { entity.VerifyNotEditing(); bool entityRequiresValidation = entity.MetaType.RequiresValidation; EntityAction customMethod = entity.EntityActions.SingleOrDefault(); if (!entityRequiresValidation && customMethod == null) { continue; } if (entity.EntityState == EntityState.Deleted) { // skip validation for Deleted entities here since the entity is going to be deleted anyway continue; } // first validate the entity List <ValidationResult> validationResults = new List <ValidationResult>(); if (entityRequiresValidation) { ValidationUtilities.TryValidateObject(entity, validationContext, validationResults); } // validate any Custom Method invocations if (customMethod != null) { // validate the method call object[] parameters = customMethod.HasParameters ? customMethod.Parameters.ToArray() : null; ValidationContext customMethodValidationContext = ValidationUtilities.CreateValidationContext(entity, validationContext); ValidationUtilities.TryValidateCustomUpdateMethodCall(customMethod.Name, customMethodValidationContext, parameters, validationResults); } if (validationResults.Count > 0) { // replace the validation errors for the entity IEnumerable <ValidationResult> entityErrors = new ReadOnlyCollection <ValidationResult>(validationResults.Select(err => new ValidationResult(err.ErrorMessage, err.MemberNames)).Distinct(new ValidationResultEqualityComparer()).ToList()); ValidationUtilities.ApplyValidationErrors(entity, entityErrors); success = false; } else { // clear the errors for the entity entity.ValidationErrors.Clear(); } } return(success); }
/// <summary> /// When a result is manually added to the collection, we must add it /// to our parents collection. /// </summary> /// <param name="item">The result to add</param> protected override void OnAdd(ValidationResult item) { if (this._complexObject._parent != null) { // transform the error by adding our parent property to the member names item = ValidationUtilities.ApplyMemberPath(item, this._complexObject._parentPropertyName); // add the result to our parents error collection ICollection <ValidationResult> resultCollection = GetValidationResults(this._complexObject._parent); resultCollection.Add(item); } }
/// <summary> /// Cancels the edit session, reverting all changes made to the /// entity since the session began. /// </summary> public void Cancel() { // revert any data member modifications if (this._snapshot != null) { ObjectStateUtility.ApplyState(this._instance, this._snapshot); } // Revert the validation errors and notify our parent ValidationUtilities.ApplyValidationErrors(this._instance, this._validationErrors); this._instance.NotifyParentMemberValidationChanged(null, this._validationErrors); }
/// <summary> /// Get the <see cref="ValidationContext"/> to be used for validation invoked /// from this <see cref="ComplexObject"/>. /// </summary> /// <returns> /// A new <see cref="ValidationContext"/> instance, using the /// <see cref="EntityContainer.ValidationContext"/> as the parent context /// if available. /// </returns> private ValidationContext CreateValidationContext() { // Get the validation context from the entity container if available, // otherwise create a new context. ValidationContext parentContext = null; Entity rootEntity = this.Entity; if (rootEntity != null && rootEntity.EntitySet != null && rootEntity.EntitySet.EntityContainer != null) { parentContext = rootEntity.EntitySet.EntityContainer.ValidationContext; } return(ValidationUtilities.CreateValidationContext(this, parentContext)); }
private void NotifyParentMemberValidationChanged(string propertyName, IEnumerable <ValidationResult> validationResults) { if (this.IsAttached) { // notify our parent of the errors, appending the property path to the results IEnumerable <ValidationResult> parentValidationResults = ValidationUtilities.ApplyMemberPath(validationResults, this._parentPropertyName); string propertyPath = this._parentPropertyName; if (!string.IsNullOrEmpty(propertyName)) { propertyPath = propertyPath + "." + propertyName; } this._onMemberValidationChanged(propertyPath, parentValidationResults); } }
/// <summary> /// When a result is manually removed from the collection, we must remove /// it from our parents collection. /// </summary> /// <param name="item">The result to remove</param> protected override void OnRemove(ValidationResult item) { if (this._complexObject._parent != null) { // transform the error by adding our parent property to the member names item = ValidationUtilities.ApplyMemberPath(item, this._complexObject._parentPropertyName); // search (by value) for the item in our parents error collection ICollection <ValidationResult> resultCollection = GetValidationResults(this._complexObject._parent); ValidationResultEqualityComparer comparer = new ValidationResultEqualityComparer(); item = resultCollection.FirstOrDefault(p => comparer.Equals(p, item)); if (item != null) { resultCollection.Remove(item); } } }
/// <summary> /// Commit the edits made to this instance since the last call /// to BeginEdit /// </summary> protected void EndEdit() { if (!this.IsEditing) { return; } // TODO : Check if this old comment is still true and if this is something we should manage // " The desktop version of the framework doesn't currently do deep validation." // Validate the instance itself (cross-field validation happens here) List <ValidationResult> validationResults = new List <ValidationResult>(); ValidationUtilities.TryValidateObject(this, this.CreateValidationContext(), validationResults); // Replace all errors for this instance and notify our parent ValidationUtilities.ApplyValidationErrors(this, validationResults); this.NotifyParentMemberValidationChanged(null, validationResults); this._editSession = null; }
/// <summary> /// Commit the edits made to this instance since the last call /// to BeginEdit /// </summary> protected void EndEdit() { if (!this.IsEditing) { return; } #if SILVERLIGHT // Validate the instance itself (cross-field validation happens here) List <ValidationResult> validationResults = new List <ValidationResult>(); ValidationUtilities.TryValidateObject(this, this.CreateValidationContext(), validationResults); // Replace all errors for this instance and notify our parent ValidationUtilities.ApplyValidationErrors(this, validationResults); this.NotifyParentMemberValidationChanged(null, validationResults); #else // Validate the instance itself (cross-field validation happens here) // TODO : The desktop version of the framework doesn't currently do // deep validation. Validator.ValidateObject(this, this.CreateValidationContext(), /*validateAllProperties*/ true); #endif this._editSession = null; }