/// <summary> /// Sets the value of a specific property. /// </summary> /// <param name="property">The property to set.</param> /// <param name="value">Value of the property.</param> /// <param name="notifyOnChange">If <c>true</c>, the <see cref="INotifyPropertyChanged.PropertyChanged"/> event will be invoked.</param> /// <exception cref="PropertyNotNullableException">The property is not nullable, but <paramref name="value"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException">The <paramref name="property"/> is <c>null</c>.</exception> protected internal void SetValue <TValue>(PropertyData property, TValue value, bool notifyOnChange = true) { Argument.IsNotNull("property", property); // Is the object currently read-only (and aren't we changing that)? if (IsReadOnly || _isFrozen) { if (property != IsReadOnlyProperty) { Log.Warning("Cannot set property '{0}', object is currently read-only", property.Name); return; } } if (property.IsCalculatedProperty) { Log.Warning("Cannot set property '{0}', the property is a calculated property", property.Name); return; } if ((value != null) && !property.Type.IsInstanceOfTypeEx(value)) { if (!value.GetType().IsCOMObjectEx()) { throw Log.ErrorAndCreateException(msg => new InvalidPropertyValueException(property.Name, property.Type, value.GetType()), "Cannot set value '{0}' to property '{1}' of type '{2}', the value is invalid", value, property.Name, GetType().FullName); } } var notify = false; TValue oldValue; lock (_lock) { var changeNotificationsSuspensionContext = _changeNotificationsSuspensionContext; oldValue = GetValueFromPropertyBag <TValue>(property.Name); var areOldAndNewValuesEqual = ObjectHelper.AreEqualReferences(oldValue, value); if (!areOldAndNewValuesEqual) { SetValueToPropertyBag(property.Name, value); } notify = (notifyOnChange && (AlwaysInvokeNotifyChanged || !areOldAndNewValuesEqual)); if (changeNotificationsSuspensionContext != null) { changeNotificationsSuspensionContext.Add(property.Name); notify = false; } } // Notify outside lock if (notify) { RaisePropertyChanged(property.Name, BoxingCache.GetBoxedValue(oldValue), BoxingCache.GetBoxedValue(value)); } }