/// <summary> /// Raises this object's PropertyChanged event for one property and all its dependent /// properties. /// </summary> /// <param name="propertyName">The name of the property that has a new value.</param> protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { // Verify that the notified property actually exists in the current object. This can // reveal misspelled properties and missing notifications. It's only checked in Debug // builds for performance and stability reasons. #if DEBUG if (!TypeDescriptor.GetProperties(this).OfType <PropertyDescriptor>().Any(d => d.Name == propertyName)) { throw new ArgumentException("Notifying a change of non-existing property " + this.GetType().Name + "." + propertyName); } #endif // Call On…Changed methods that are marked with the [PropertyChangedHandler] attribute foreach (var changeHandler in PropertyChangedHandlers.GetValuesOrEmpty(propertyName)) { changeHandler(); } // Raise PropertyChanged event, if there is a handler listening to it var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } // Also notify changes for dependent properties // (This could be moved inside the (handler != null) check for improved performance, but // then it could miss out On…Changed method calls for dependent properties, which might // be a nice feature.) foreach (var dependentPropertyName in DependentNotifications.GetValuesOrEmpty(propertyName)) { OnPropertyChanged(dependentPropertyName); } }
/// <summary> /// Raises this object's PropertyChanged event. /// </summary> private void RaisePropertyChanged(string propertyName, bool notifyDependentProperties, IDictionary <string, object> processedProperties, IDictionary <ICommand, object> processedCommands) { if (processedProperties.ContainsKey(propertyName)) { return; } var eventArgs = new PropertyChangedEventArgs(propertyName); if (PropertyChanged != null) { Dispatch(() => PropertyChanged(this, eventArgs)); } // ReSharper disable AssignNullToNotNullAttribute processedProperties.Add(propertyName, null); // ReSharper restore AssignNullToNotNullAttribute if (!notifyDependentProperties) { return; } if (DependentNotifications.TryGetValue(propertyName, out var dependentPropertyNotifications)) { foreach (var dependentProperty in dependentPropertyNotifications) { RaisePropertyChanged(dependentProperty, true, processedProperties, processedCommands); } } if (DependentCommandNotifications.TryGetValue(propertyName, out var dependendCommandNotifications)) { foreach (var dependentCommand in dependendCommandNotifications) { if (processedCommands.ContainsKey(dependentCommand)) { continue; } if (dependentCommand is RelayCommand relayCommand) { relayCommand.RaiseCanExecuteChanged(); } // ReSharper disable AssignNullToNotNullAttribute processedCommands.Add(dependentCommand, null); // ReSharper restore AssignNullToNotNullAttribute } } }
/// <summary> /// Adds a new entry to the list of dependent property notifications. /// </summary> /// <typeparam name="TSource">the type of the source property</typeparam> /// <typeparam name="TDepend">the type of the dependent property</typeparam> public virtual void AddPropertyChangedNotification <TSource, TDepend>( Expression <Func <TSource> > sourcePropertyAccessor, params Expression <Func <TDepend> >[] dependentPropertyAccessors) { var basePropertyName = GetPropertyName(sourcePropertyAccessor); foreach (var dependentPropertyName in dependentPropertyAccessors .Select(GetPropertyName) .Where(dependentPropertyName => basePropertyName != dependentPropertyName)) { if (!DependentNotifications.TryGetValue(basePropertyName, out var notifications)) { notifications = new List <string>(); DependentNotifications.Add(basePropertyName, notifications); } notifications.Add(dependentPropertyName); } }
public void OnPropertyChanged([CallerMemberName] string property = "") { #if DEBUG if (!TypeDescriptor.GetProperties(this).OfType <PropertyDescriptor>().Any(d => d.Name == property)) { throw new ArgumentException("Notifying a change of non-existing property " + GetType().Name + "." + property); } #endif if (PropertyChanged != null) { InvokeOnMainThread(() => PropertyChanged(this, new PropertyChangedEventArgs(property))); } foreach (string dependentProperty in DependentNotifications.GetValuesOrEmpty(property)) { OnPropertyChanged(dependentProperty); } }