public void HandleChange(IBehaviorContext context, ChangeArgs args) { // We eagerly refresh the caches of all ancestors. Consider the case: // (1) A validation result change is notified, thus all caches up the // hierarchy hold invalid validation states. // (2) The next behavior in this chain may access the cached validation // result of an ancestor (this is actually the case with the // 'CollectionValidationController'). // // Note that we do not handle changes that originated from an descendant // because we have already handled them (the caches of all ancestors were // cleared when the change was handled on that descendant). if (args.ChangeType == ChangeType.ValidationResultChanged) { bool isChangeOfSelf = !args.ChangedPath.SelectsAncestor(); if (isChangeOfSelf) { InvalidateCache(context); InvalidateParentCachesOf(context.VM); } } this.HandleChangedNext(context, args); }
private void NotifyChangeCore(ChangeArgs args) { CallPropertyChangedHandlerBehaviors(args); CallChangeHandlerBehaviors(args); ForwardChangeNotificationToParents(args); ForwardChangeToViewModel(args); }
// If an already invalid child is set or the previous child was invalid, // the aggregated validation state of the owner changes, therefore an // ValidationResultChanged event should be raised. private void DetectValidationResultChange(IBehaviorContext context, Action action) { IViewModel oldChild = this.GetValueNext <TValue>(context); action(); IViewModel newChild = this.GetValueNext <TValue>(context); // It is important to query the 'oldResult' after executing the 'action'. The // following scenario could happen otherwise: // 1. 'oldResult' is assigned before the action and is valid. // 2. The action is executed and makes 'oldChild' invalid and 'newChild' // stays valid. Since 'oldChild' is still in the hierarchy at this // time, the error is propagated to the validation caches of the // parent. // 3. 'newResult' is assigned to result of the 'newChild' (valid). // 4. We would not detect a change in the 'if' below and therefore not // raise a change which would leave the validation cache of the parents // with the stale error. ValidationResult oldResult = GetValidationResultOrValidIfNull(oldChild); ValidationResult newResult = GetValidationResultOrValidIfNull(newChild); if (!Object.Equals(oldResult, newResult)) { context.NotifyChange(ChangeArgs.ValidationResultChanged()); } }
public void HandleChange(IBehaviorContext context, ChangeArgs args) { var c = GetCache(context); c.HandleChange(context, args); this.HandleChangedNext(context, args); }
public void HandleChange(IBehaviorContext context, ChangeArgs args) { foreach (var depedency in _dependencies) { depedency.HandleChange(context.VM, args); } this.HandleChangedNext(context, args); }
public override void Execute( IViewModel ownerVM, ChangeArgs args, DeclarativeDependency dependency ) { _action((TOwnerVM)ownerVM, args); }
public override bool Equals(object obj) { ChangeArgs other = obj as ChangeArgs; return (other != null && other.ChangeType == ChangeType && other.ChangedVM == ChangedVM && other.ChangedProperty == ChangedProperty); }
public void HandlePropertyChanged(IBehaviorContext context, ChangeArgs args) { // Only clear the cache, if the value was successfully set on the next stage // (Value for DisplayValue or ValidatedValue for Value). if (args.Stage.Sequence > _stage.Sequence) { _invalidValueCache.Clear(context); } this.HandlePropertyChangedNext(context, args); }
private void ForwardChangeNotificationToParents(ChangeArgs args) { // Parents have to be cached, because parents may changed by change handlers (declarative dependencies). foreach (var parent in Parents.ToArray()) { parent .Kernel .GetContext() .NotifyChange(args); } }
public virtual void NotifyPropertyChanged(IBehaviorContext context, ValueStage stage, TValue oldValue, TValue newValue) { var args = ChangeArgs.PropertyChanged( _property, stage, reason: null ); context.NotifyChange(args); this.NotifyPropertyChangedNext(context, stage, oldValue, newValue); }
public void HandleChange(IViewModel ownerVM, ChangeArgs args) { bool isExpectedChangeType = _changeTypes.Contains(args.ChangeType); if (!isExpectedChangeType) { return; } PathMatch sourcePathMatch = _sourcePath.Matches(args.ChangedPath); if (sourcePathMatch.Success) { _action.Execute(ownerVM, args, this); } }
public void HandlePropertyChanged(IBehaviorContext context, ChangeArgs args) { AssertInitialized(); if (_descriptor != null) { _descriptor.RaiseValueChanged(context.VM); } IHandlePropertyChangedBehavior next; if (TryGetBehavior(out next)) { next.HandlePropertyChanged(context, args); } }
public void HandleChange(IBehaviorContext context, CollectionChangedArgs <TItemVM> args) { var c = args.Collection; var oldItems = (IEnumerable <IViewModel>)args.OldItems; var newItems = (IEnumerable <IViewModel>)args.NewItems; ChangeArgs a; switch (args.Type) { // No change of 'ItemsRemoved' is raised to give the client a chance // to distinguish if the removal was due to a repopulation (Type = // 'Populated' and 'OldItems' contains items) or if the removal was // triggered by a 'Clear', 'Remove' or 'SetItem'. case CollectionChangeType.Populated: a = ChangeArgs.CollectionPopulated(c, oldItems, args.Reason); context.NotifyChange(a); break; } switch (args.Type) { case CollectionChangeType.ItemRemoved: case CollectionChangeType.ItemSet: case CollectionChangeType.ItemsCleared: if (args.OldItems.Any()) { a = ChangeArgs.ItemsRemoved(c, oldItems, args.Reason); context.NotifyChange(a); } break; } switch (args.Type) { case CollectionChangeType.ItemAdded: case CollectionChangeType.ItemSet: a = ChangeArgs.ItemsAdded(c, newItems, args.Reason); context.NotifyChange(a); break; } this.HandleChangeNext(context, args); }
public void HandleChange(IBehaviorContext context, CollectionChangedArgs <TItemVM> args) { IEnumerable <TItemVM> changedItems = args .OldItems .Concat(args.NewItems); IEnumerable <ValidationResult> changedItemsResults = changedItems .Select(x => x.Kernel.GetValidationResult()); var changedItemsResult = ValidationResult.Join(changedItemsResults); this.HandleChangeNext(context, args); // If already invalid items are added or removed, the aggregated // validation state of the collection owner changes, therefore an // ValidationResultChanged event should be raised. if (!changedItemsResult.IsValid) { context.NotifyChange(ChangeArgs.ValidationResultChanged(args.Reason)); } }
//internal IList<IPropertySelector> TargetProperties { // get { return _targetProperties; } //} public override void Execute( IViewModel ownerVM, ChangeArgs args, DeclarativeDependency dependency ) { _target.Revalidate(ownerVM); //if (TargetPath.IsEmpty) { // RevalidateProperties(ownerVM); //} else { // var viewModels = TargetPath.GetDescendants(ownerVM); // foreach (var viewModel in viewModels) { // if (_targetProperties.Count > 0) { // RevalidateProperties(viewModel); // } else { // viewModel.Kernel.Revalidate(ValidationScope.SelfAndLoadedDescendants); // } // } //} }
private void CallPropertyChangedHandlerBehaviors(ChangeArgs args) { if (args.ChangeType != ChangeType.PropertyChanged) { return; } var result = args .ChangedPath .SelectsOnlyPropertyOf(_vm); bool ownPropertyChanged = result.Success; if (ownPropertyChanged) { result .Property .Behaviors .HandlePropertyChangedNext(GetContext(), args); } }
public void Refresh(IBehaviorContext context, RefreshOptions options) { RequireInitialized(); var previousValue = GetValue(context); RefreshCache(context); var newValue = GetValue(context); if (!Object.Equals(newValue, previousValue)) { var args = ChangeArgs.ViewModelPropertyChanged( _property, ValueStage.ValidatedValue, previousValue, newValue, RefreshReason.Create(options.ExecuteRefreshDependencies) ); context.NotifyChange(args); } this.RefreshNext(context, options); }
public override void InitializeValue(IBehaviorContext context) { base.InitializeValue(context); TValue childVM = this.GetValueNext <TValue>(context); if (childVM != null) { ValidationResult childValidatonResult = childVM .Kernel .GetValidationResult(); if (!childValidatonResult.IsValid) { // If 'PopulatedWith' returns an already invalid item, the aggregated // validation state of the collection owner changes, therefore an // 'ValidationResultChanged' event should be raised. if (!childValidatonResult.IsValid) { context.NotifyChange(ChangeArgs.ValidationResultChanged()); } } } }
public void HandleChange(IBehaviorContext context, ChangeArgs args) { _changeHandler((TVM)context.VM, args); this.HandleChangedNext(context, args); }
// We eagerly refresh the caches of all ancestors. Consider the case: // (1) A validation result change is notified, thus all caches up the // hierarchy hold invalid validation states. // (2) The next behavior in this chain may access the cached validation // result of an ancestor (this is actually the case with the // 'CollectionValidationController'). // // Note that we do not handle changes that originated from an descendant // because we have already handled them (the caches of all ancestors were // cleared when the change was handled on that descendant). public void HandleChange(IBehaviorContext context, ChangeArgs args) { bool refreshDescendants = false; bool resultsChanged = false; var self = context.VM; switch (args.ChangeType) { case ChangeType.ValidationResultChanged: var ownViewModelResultChanged = args .ChangedPath .SelectsOnly(self) .Success; if (ownViewModelResultChanged) { RefreshViewModelResult(context); resultsChanged = true; } else { var ownPropertyResultChanged = args .ChangedPath .SelectsOnlyPropertyOf(self) .Success; if (ownPropertyResultChanged) { RefreshPropertiesResult(context); resultsChanged = true; } } break; case ChangeType.PropertyChanged: var ownViewModelPropertyMayHaveChanged = args .ChangedPath .SelectsOnlyPropertyOf(self) .Success; refreshDescendants = ownViewModelPropertyMayHaveChanged; break; case ChangeType.AddedToCollection: case ChangeType.RemovedFromCollection: var ownCollectionContentsChanged = args .ChangedPath .SelectsOnlyCollectionOf(self) .Success; refreshDescendants = ownCollectionContentsChanged; break; } if (refreshDescendants) { RefreshChildren( context, removedChildren: args.OldItems, newChildren: args.NewItems ); } else if (resultsChanged) { RefreshDerivedResults(); NotifyBehaviorOfParent(context); } }
void IBehaviorContext.NotifyChange(ChangeArgs args) { Check.NotNull(args, nameof(args)); NotifyChangeCore(args.PrependViewModel(_vm)); }
private void ForwardChangeToViewModel(ChangeArgs args) { _vm.NotifyChange(args); }
private void CallChangeHandlerBehaviors(ChangeArgs args) { _descriptor .Behaviors .HandleChangedNext(this, args); }
//internal IList<IPropertySelector> TargetProperties { // get { return _targetProperties; } //} public override void Execute( IViewModel ownerVM, ChangeArgs args, DeclarativeDependency dependency ) { RefreshReason reason = args.Reason as RefreshReason; if (reason != null && !reason.ExecuteRefreshDependencies) { return; } RefreshTrace.BeginRefresh(dependency); _target.ForeachLoadedDescendant(ownerVM, (vm, props) => { if (props.Any()) { // TODO: The logic with 'wouldRefreshChangeSource' is not correct. The refresh source // may be an descendant of 'vm' in which case it would nevertheless be refreshed. // Unit test 'SetValue_WhenValidationResultChanges_WorksWithSelfRecursiveDependency' // reproduces this. foreach (var prop in props) { bool wouldRefreshChangeSource = vm == args.ChangedVM && prop == args.ChangedProperty; if (!wouldRefreshChangeSource) { vm.Kernel.RefreshInternal(prop, new RefreshOptions(_executeRefreshDependencies)); } } } else { bool wouldRefreshChangeSource = vm == args.ChangedVM; if (!wouldRefreshChangeSource) { vm.Kernel.RefreshInternal(_executeRefreshDependencies); } } }); //_target.Refresh(ownerVM, _executeRefreshDependencies); //ownerVM.Kernel.RefreshInternal(_target, _executeRefreshDependencies); //if (TargetPath.IsEmpty) { // if (_targetProperties.Count > 0) { // RefreshProperties(ownerVM); // } else { // ownerVM.Kernel.RefreshInternal(_executeRefreshDependencies); // } //} else { // var viewModels = TargetPath.GetDescendants(ownerVM); // foreach (var viewModel in viewModels) { // if (_targetProperties.Count > 0) { // RefreshProperties(viewModel); // } else { // viewModel.Kernel.RefreshInternal(_executeRefreshDependencies); // } // } //} RefreshTrace.EndLastRefresh(); }