如何防止无限的属性变化

时间:2011-07-14 16:53:18

标签: c# xaml inotifypropertychanged

假设我有销售价格,首付金额,首付比例和贷款金额。当用户更改任何这些属性时,需要更新其他属性以反映新值。你如何处理这种类型的无限属性变化事件?

5 个答案:

答案 0 :(得分:4)

当需要跨多个属性进行流控制时,我将建立一个流量控制变量 - 一个布尔值 - 并且在每个被更改的属性中,我将添加一个测试,以查看我是否处于流量控制之下。

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;
        }
    }
}

这样,无论属性如何更改都可以启动其他属性的更改,但是当它们发生更改时,它们将不会依次启动它们自己的更改集。

如果可以使用计算结果,您还应该尽可能多地阅读这些属性,以便限制对象的更改方式。

答案 1 :(得分:2)

最简单的方法是,如果该属性确实更改,则仅提出更改事件:

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
        }
   }
}

答案 2 :(得分:1)

我不确定我是否完全理解,因为我不知道你的意思是什么'无限'

这可能是用字段实际支持属性的一个很好的用例。这样,您可以在Property集上触发事件,但在内部设置一个字段,而不触发N个事件。

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
            }
        }
    }

答案 3 :(得分:0)

如果确实需要INotifyPropertyChanged来通知外部对象,那么我只会集中所有内容。像这样:

    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");
    }

也许你可以用更少的方法甚至单个方法集中重新计算,但我不知道你如何计算它们。但是,在重新计算值时,您必须保留特定的顺序。 由于它们只对字段进行操作而不更改属性,因此不会有PropertyChanged-feedback-loop。

希望这会有所帮助,我没有误解你的想法。

答案 4 :(得分:0)

OP想要的是跟随

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));
        }
    }
}

他可能正在做的是处理他提到的每个属性的setter中的其他属性,从而导致setter的循环调用。

维杰