开发者

how to prevent infinite property change

开发者 https://www.devze.com 2023-03-20 04:07 出处:网络
Lets say I have sales price, down payment amount, down payment percent and loan amount.When any of these properties are changed by the user the others need to be updated to reflect the new values.How

Lets say I have sales price, down payment amount, down payment percent and loan amount. When any of these properties are changed by the user the others need to be updated to reflect the new values. How 开发者_开发问答do you deal with this type of infinite property change events?


When flow control is necessary across multiple attributes, I'll institute a flow control variable - a boolean - and in each property that's being changed, I'll add a test to see if I'm under flow control or not.

private bool controlledChange = false;

public property int MyVal1
{
    set 
    {
        _myVal1 = value;
        if(!controlledChange)
        {
            controlledChange = true;
            MyVal2 -= 1;
            controlledChange = false;
        }
    }
}

public property int MyVal2
{
    set 
    {
        _myVal2 = value;
        if(!controlledChange)
        {
            controlledChange = true;
            MyVal1 += 1;
            controlledChange = false;
        }
    }
}

This way whatever property is changed can initiate changes across the other properties, but when they get changed, they will no NOT to initiate their own set of changes in turn.

You should also look to make as many of those properties read only as possible, if they can have calculated results, so that you limit how the object can be changed.


THe easiest way is to only raise a change event if the property has really changed:

public decimal SalePrice {
   get{
       return salePrice;
   }
   set {
        if (salePrice != value) {
          salePrice = value; // putting as first statement prevents the setter 
                             // to be entered again ...
          RaiseSalePriceChange();
          // Set other properties
        }
   }
}


I'm not sure I completely understand, since I don't know what you mean by 'infinite'

This may be a good use case for actually backing your properties with fields. That way, you can trigger events on Property sets, but internally set the fields one at a time without triggering N events.

class MyClass
{
    private string m_Name;
    private int m_SomeValue;

    public string Name
    {
        get { return m_Name; }
        set
        {
            if (value != m_Name)
            {
                m_Name = value;
                m_SomeValue++;

                // Raise Event
            }
        }
    }

    public int SomeValue
    {
        get { return m_SomeValue; }
        set
        {
            if (m_SomeValue != value)
            {
                m_SomeValue = value;
                // Raise Event
            }
        }
    }


If INotifyPropertyChanged is really needed to notify external objects, so I would just centralise everything. Like this:

    private double salesPrice;
    private double downPaymentAmount;
    private double downPaymentPercent;
    private double loanAmount;

    public double SalesPrice
    {
        get
        {
            return salesPrice;
        }
        set
        {
            if (salesPrice != value)
            {
                salesPrice = value;

                // maybe you would rather use a RecalculateForSalePriceChanged() method
                RecalculateDownPaymentAmount();
                RecalculateDownPaymentPercent();
                RecalculateLoanAmount();

                propertiesChanged();
            }
        }
    }

    public double DownPaymentAmount
    {
        get
        {
            return downPaymentAmount;
        }
        set
        {
            if (downPaymentAmount != value)
            {
                downPaymentAmount = value;

                // see above
                RecalculateDownPaymentPercent();
                RecalculateLoanAmount();
                RecalculateSalesPrice();

                propertiesChanged();
            }
        }
    }

    public double DownPaymentPercent
    {
        get
        {
            return downPaymentPercent;
        }
        set
        {
            if (downPaymentPercent != value)
            {
                downPaymentPercent = value;

                // see above
                RecalculateDownPaymentAmount();
                RecalculateLoanAmount();
                RecalculateSalesPrice();

                propertiesChanged();
            }
        }
    }

    public double LoanAmount
    {
        get
        {
            return loanAmount;
        }
        set
        {
            if (loanAmount != value)
            {
                loanAmount = value;

                // see above
                RecalculateDownPaymentAmount();
                RecalculateDownPaymentPercent();
                RecalculateSalesPrice();

                propertiesChanged();
            }
        }
    }

    private void propertiesChanged()
    {
        RaisePropertyChanged("SalesPrice", "DownPaymentAmount", "DownPaymentPercent", "LoanAmount");
    }

Maybe you can concentrate the recalculations in less methods or even a single one, but I do not know how you calculate them. But certainly you have to keep a specific order when recalculating the values. Since they only operate on fields and do not change the properties, there will be no PropertyChanged-feedback-loop.

Hope this helps and I did not misunderstood what you wanted.


What the OP wanted was something like following

class A : INotifyPropertyChanged
{
    private int field1;
    public int Property1
    {
        get { return field1; }
        set
        {
            field1 = value;
            field2++;
            RaisePropertyChanged("Property1");
            RaisePropertyChanged("Property2");
        }
    }

    private int field2;
    public int Property2
    {
        get { return field2; }
        set
        {
            field2 = value;
            field1++;
            RaisePropertyChanged("Property1");
            RaisePropertyChanged("Property2");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

What he might be doing was handling other properties in the setter of each property he mentioned thus leading to cyclic invocation of setters.

Vijay

0

精彩评论

暂无评论...
验证码 换一张
取 消