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 pretty sure it must be possible in a declarative way, but my first attempt to solve this issue have been a failure. The solution i want to accomplish is using Lambda Expressions to define this. Since Expressions can be parsed (??) it should be possible to parse the expressions and attach to all NotifyPropertyChanged events to get notified about depended data changes.
in ContinousLinq, this works excellent for collections.
private SelfUpdatingExpression<int> m_fooExp = new SelfUpdatingExpression<int>(this, ()=> Foo * Foo);
public int Foo
{
get
{
return m_fooExp.Value;
}
}
but unfortionatly i lack on fundamentional know how in Expressions and Linq :(
One way to indicate that bar has changed is to add a call to onPropertyChanged(this, "bar")
in the foo setter. Ugly as hell, I know, but there you have it.
If foo is defined in an ancestor class or you otherwise don't have access to the implementation of the setter, I suppose you could subscribe to the PropertyChanged event so that when you see a "foo" change, you can also fire a "bar" change notification. Subscribing to events on your own object instance is equally ugly, but will get the job done.
If you are only using bar for UI purposes, you could remove it from your model completely. You could bind the UI element to the foo property and use a custom value converter to change the result from foo into foo*foo.
In WPF there are often a lot of ways to accomplish the same thing. Often times, there isn't a correct way, just a personal preference.
Depending on the expense of the calculation and how frequently you expect it to be used, it may be beneficial to make it a private set property and calculate the value when foo
is set, rather than calculating on the fly when the bar
get is called. This is basically a caching solution and then you can do the property change notification as part of the bar
private setter. I generally prefer this approach, mainly because I use AOP (via Postsharp) to implement the actual INotifyPropertyChanged
boilerplate.
-Dan
You could simply call
OnPropertyChanged(this, "bar");
from anywhere in this class...You cold even go like this:
public raz()
{
this.PropertyChanged += new PropertyChangedEventHandler(raz_PropertyChanged);
}
void raz_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "foo")
{
onPropertyChanged(this, "bar");
}
}
If this is a serious issue (by "serious", I mean you have a non-trivial number of dependent read-only properties), you can make a property dependency map, e.g.:
private static Dictionary<string, string[]> _DependencyMap =
new Dictionary<string, string[]>
{
{"Foo", new[] { "Bar", "Baz" } },
};
and then reference it in OnPropertyChanged:
PropertyChanged(this, new PropertyChangedEventArgs(propertyName))
if (_DependencyMap.ContainsKey(propertyName))
{
foreach (string p in _DependencyMap[propertyName])
{
PropertyChanged(this, new PropertyChangedEventArgs(p))
}
}
This isn't inherently a lot different from just putting multiple OnPropertyChanged
calls in the Foo
setter, since you have to update the dependency map for every new dependent property you add.
But it does make it possible to subsequently implement a PropertyChangeDependsOnAttribute
and use reflection to scan the type and build the dependency map. That way your property would look something like:
[PropertyChangeDependsOn("Foo")]
public int Bar { get { return Foo * Foo; } }