views:

84

answers:

5

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 (in this case a textbox and a read-only textbox. For example:

public class raz : INotifyPropertyChanged
{

  int _foo;
  public int foo
  {
    get
    {
      return _foo;
    }
    set
    {
      _foo = value;
      onPropertyChanged(this, "foo");
    }
  }

  public int bar
  {
    get
    {
      return foo*foo;
    }
  }

  public raz()
  {

  }

  public event PropertyChangedEventHandler PropertyChanged;
  private void onPropertyChanged(object sender, string propertyName)
  {
    if(this.PropertyChanged != null)
    {
      PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
    }
  }
}

My understanding is that bar will not automatically update the UI when foo is modified. Whats the correct way to do this?

+4  A: 

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.

dthorpe
I don't understand why you think it is particularly ugly to fire onPropertyChanged(this, "bar")? I could see it if .bar was dependant on 3 properties and you had that call in all three setters... but then he could move the calculation out of the property-getter of .bar and into a calculation-method that calls the update method.
Goblin
It's ugly because you're placing logic required for proper behavior of property B in the setter of property A. There can be any number of properties that are dependent upon the value of A. Having to modify A to satisfy the needs of other properties that use A is nonobvious and nonscalable.
dthorpe
A cleaner solution would be to have some sort of way to indicate that B is dependent upon A and that when A changes B should signal a value change as well. The 2nd option above, to listen to one's own PropertyChanged event, is in this style, but listening to your own events is kinda kinky too.
dthorpe
Hehe - I think you have a lower threshold than me for what constitutes ugly code... :P I've learned to 'appreciate' UI-logic that isn't an event-soup...
Goblin
Quite possible. My background is in building APIs and app frameworks where everyone sees the code. We can get away with a lot of stuff in an app that would not be allowed in a framework or API. ;>
dthorpe
Yeah this was what I thought also a little bit after posting the question. I agree its not the most aesthetically pleasing
tbischel
A: 

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

Dan Bryant
+1  A: 

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");
        }
    }
Tokk
This seems like a better scalable solution when I need to repeat for a bunch of properties.
tbischel
A: 

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; } }
Robert Rossney
+1  A: 

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.

mdm20
in my case, the user needs to see it and the program needs to access it as well, but that does sound interesting.
tbischel