I am trying to understand how to update the UI if I have a read-only property that is dependent on another property, so that changes to one property update both UI elements
I realize this is an old question, but it's the first Google result of "NotifyPropertyChanged of linked properties", so I think it's appropriate to add this answer so that there's some concrete code.
I used Robert Rossney's suggestion and created a custom attribute, then used it in a base view model's PropertyChanged event.
The attribute class:
[AttributeUsage(AttributeTargets.Property,AllowMultiple = true)]
public class DependsOnPropertyAttribute : Attribute
{
public readonly string Dependence;
public DependsOnPropertyAttribute(string otherProperty)
{
Dependence = otherProperty;
}
}
And in my base view model (which all other WPF view models inherit from):
public abstract class BaseViewModel : INotifyPropertyChanged
{
protected Dictionary<string, List<string>> DependencyMap;
protected BaseViewModel()
{
DependencyMap = new Dictionary<string, List<string>>();
foreach (var property in GetType().GetProperties())
{
var attributes = property.GetCustomAttributes<DependsOnPropertyAttribute>();
foreach (var dependsAttr in attributes)
{
if (dependsAttr == null)
continue;
var dependence = dependsAttr.Dependence;
if (!DependencyMap.ContainsKey(dependence))
DependencyMap.Add(dependence, new List<string>());
DependencyMap[dependence].Add(property.Name);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler == null)
return;
handler(this, new PropertyChangedEventArgs(propertyName));
if (!DependencyMap.ContainsKey(propertyName))
return;
foreach (var dependentProperty in DependencyMap[propertyName])
{
handler(this, new PropertyChangedEventArgs(dependentProperty));
}
}
}
This now allows me to mark properties easily, like so:
public int NormalProperty
{
get {return _model.modelProperty; }
set
{
_model.modelProperty = value;
OnPropertyChanged();
}
}
[DependsOnProperty(nameof(NormalProperty))]
public int CalculatedProperty
{
get { return _model.modelProperty + 1; }
}