C# 如何防止无限属性变化

C# 如何防止无限属性变化,c#,xaml,inotifypropertychanged,C#,Xaml,Inotifypropertychanged,假设我有销售价格、首付金额、首付百分比和贷款金额。当用户更改其中任何属性时,需要更新其他属性以反映新值。如何处理这种类型的无限属性更改事件?最简单的方法是仅在属性确实发生更改时引发更改事件: 最简单的方法是仅在属性确实发生更改时引发更改事件: 当需要跨多个属性进行流控制时,我将建立一个流控制变量(一个布尔值),并在正在更改的每个属性中添加一个测试,以查看我是否处于流控制之下 private bool controlledChange = false; public property int M

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

最简单的方法是仅在属性确实发生更改时引发更改事件:


最简单的方法是仅在属性确实发生更改时引发更改事件:


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

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;
        }
    }
}
通过这种方式,无论更改了什么属性,都可以跨其他属性启动更改,但是当它们被更改时,它们将不需要依次启动自己的更改集


如果这些属性可以有计算结果,您还应该尽可能多地将其设置为只读,以便限制对象的更改方式。

当需要跨多个属性进行流控制时,我将在正在更改的每个属性中设置一个流控制变量-布尔值,我将添加一个测试,看看我是否处于流控制之下

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;
        }
    }
}
通过这种方式,无论更改了什么属性,都可以跨其他属性启动更改,但是当它们被更改时,它们将不需要依次启动自己的更改集


如果这些属性可以有计算结果,那么您还应该尽可能多地将它们设置为只读,以便限制对象的更改方式。

我不确定自己是否完全理解,因为我不知道您所说的“无限”是什么意思

对于实际使用字段支持属性来说,这可能是一个很好的用例。这样,您可以在属性集上触发事件,但在内部一次设置一个字段,而不触发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
            }
        }
    }

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

对于实际使用字段支持属性来说,这可能是一个很好的用例。这样,您可以在属性集上触发事件,但在内部一次设置一个字段,而不触发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
            }
        }
    }

如果确实需要
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反馈循环


希望这有帮助,我没有误解您的要求。

如果确实需要通知外部对象,则需要更改INOTIFYPROPERTYCHANGE,因此我将集中所有内容。像这样:

    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反馈循环


希望这能有所帮助,我没有误解你想要什么。

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的循环调用


Vijay

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的循环调用


Vijay

我很困惑-是什么让这个无限?在这种情况下,它与首付百分比的取整方式有关。否则,您可能会遇到这样的情况:这些值将计算相同的值,并停止触发属性更改事件。我很困惑-这是什么造成的无限?在这种情况下,它与首付款百分比的取整方式有关。否则,您可能会遇到这样的情况:这些值将计算相同的值,并停止触发属性更改事件。但是,这种类型的模式确实有一个限制,如果出于某种原因,代码集Controlled的两个部分更改为true,那么第一个“out”将在应该更改之前将其设置回false。这种情况在我的经验中通常是罕见的,但它可能会发生视情况而定。修复的时间比我在这里能进入的时间长在这种情况下,你可能会考虑引入互斥。如何在答案上放鞭炮,让每个人都能看到它及其美丽的简单性?我喜欢称这些为“STFU”布尔。但是,这种类型的模式确实有一个限制,如果出于某种原因,代码集Controlled的两个部分更改为true,那么第一个“out”将在应该更改之前将其设置回false。这种情况在我的经验中通常是罕见的,但它可能会发生视情况而定。修复的时间比我在这里能进入的时间长在这种情况下,您可能会考虑引入互斥。如何在答案上放鞭炮,以便每个人都能看到它及其美丽的简单性?