0

I am relatively new to WPF and having a problem with data binding. I am binding a dependency property of a user control to a class property in my code behind. During intantiation of the class entity in my code behind the UI is sucessfully updated through INotifyPropertyChanged. However when subsequently changing the value in my code behind the OnPropertyChangedEventHandler fires, but the OnPropertyChanged method does no longer answer to this. Below the details. It would be great if someone could give me some hints what I am doing wrong.

I implemented a user control that I am binding to a property CurrentAccProp.DiscountRate of my partial class in code behind:

<local:doubleUEdit x:Name="InterestRate" LabelField="Interest rate" MinimumValue="0" MaximumValue="1" FormatStringForNumbers="P2" IncrementSize="0.01" UncertainValue="{Binding ElementName=RibbonWindow, Path=CurrentAccProp.DiscountRate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

The class of which CurrentAccProp is an instance implements INotifyPropertyChanged to inform the UI about value changes

//Event to inform data grid about changes
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

OnPropertyChanged is called in the setter for the DiscountRate property:

doubleU discountingrate;
    public doubleU DiscountRate 
    { 
        get {return discountingrate;} 
        set 
        {
            discountingrate = value; 
            OnPropertyChanged("DiscountingRate");
        } 
    }

The property of my user control that I am binding to is implemented as a dependency property:

    //Property for data binding to doubleU
    [Description("The formatstring for the double boxes"), Category("Default")]
    public doubleU UncertainValue
    {
        get { return new doubleU(0, 0, (double)doubleUSupremum.Value, (double)doubleUSupremum.Value); }
        set { doubleURangeSlider.LowerValue = value.Interval.Infimum; doubleURangeSlider.HigherValue = value.Interval.Supremum; doubleUInfimum.Value = value.Interval.Infimum; doubleUSupremum.Value = value.Interval.Supremum; }
    }

    public static readonly DependencyProperty UncertainValueProperty =
    DependencyProperty.Register(
        "UncertainValue",
        typeof(doubleU),
        typeof(doubleUEdit),
        new PropertyMetadata(default(doubleU), OnItemsPropertyChanged));

    private static void OnItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        doubleUEdit MydblUEdt = d as doubleUEdit;

        MydblUEdt.UncertainValue = e.NewValue as doubleU;
    }

When I am instantiating CurrentAccProp in my code behind the OnPropertyChanged informs the UI and the value is updated.

AccountingProperties currentaccprop = new AccountingProperties(new doubleU(0.0));
public AccountingProperties CurrentAccProp { get { return currentaccprop; } set { currentaccprop = value; } }

However, when I later update the value of DiscountRate

CurrentAccProp.DiscountRate = new doubleU(1.0);

OnPropertyChanged gets executed, but the UI is no longer updated. Does anyone have a clue what I am doing wrong here?

The typo pointed out by HighCore and zaknotzach was indeed the problem. Thanks for your help! I implemented the approach in the thread referenced by HighCore to avoid this and it works like a charm. Below the changed AccountingProperties class from which CurrentAccProp is instantiated for reference:

public class AccountingProperties : INotifyPropertyChanged
{
    doubleU discountrate;
    public doubleU DiscountRate 
    { 
        get {return discountrate;} 
        set { SetField(ref discountrate, value, () => DiscountRate); }
    }

    //------------------------------------------------
    //constructors
    public AccountingProperties(doubleU discountrate)
    {
        DiscountRate = discountrate;
    }

    //Event to inform data grid about changes
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }


    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
    {
        if (selectorExpression == null)
            throw new ArgumentNullException("selectorExpression");
        MemberExpression body = selectorExpression.Body as MemberExpression;
        if (body == null)
            throw new ArgumentException("The body must be a member expression");
        OnPropertyChanged(body.Member.Name);
    }

    protected bool SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(selectorExpression);
        return true;
    }


}
user3731196
  • 3
  • 1
  • 3
  • 1
    First thing I notice is that your property is called `DiscountRate` but you're raising propertychanged for `DiscountingRate`. See [this answer](http://stackoverflow.com/a/1316417/643085) for a definitive way to avoid that problem. – Federico Berasategui Jun 11 '14 at 18:13
  • Wow, thanks. I bred more than two days over that and you saw it in 60 seconds. – user3731196 Jun 11 '14 at 18:39

2 Answers2

5

You need to first change the string in

OnPropertyChanged("DiscountingRate");

to "DiscountRate". The string you are giving your OnPropertyChanged function must match the property name. That is most likely the issue you are having.

zaknotzach
  • 977
  • 1
  • 9
  • 18
  • Nice catch, that is in fact the likely problem. – BradleyDotNET Jun 11 '14 at 18:20
  • Wow, thanks for your help. That did the trick. I was so focused on finding a structural flaw in my code because the update worked the first time, when I create the instance of the member behind the property. But apparently there seems to be a mechanism that informs the UI when the bound element changes its value from null to a valid value during the instantiation that I don't yet understand. – user3731196 Jun 11 '14 at 18:41
5

As already answered, the problem is OnPropertyChanged("DiscountingRate"); providing the event with an incorrect property name.

In order to prevent errors like this, you can avoid using string literals all together. In your OnPropertyChanged parameter, use CallerMemberName. You can modify your OnPropertyChanged signature to

public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
    // Do your stuff
}

Then in your setters, you just call this.OnPropertyChanged();. The method will be given the property name that was changed.

public doubleU DiscountRate 
{ 
    get {return discountingrate;} 
    set 
    {
        discountingrate = value; 
        OnPropertyChanged();
    } 
}

The benefit to this is that you can refactor your code and not worry about breaking your property changed events.

Johnathon Sullinger
  • 7,097
  • 5
  • 37
  • 102