WPF / INotifyPropertyChanged,更改txtA的值,txtB和txtC应该自动更改?

时间:2012-06-22 03:11:53

标签: wpf inotifypropertychanged

我想,一旦我改变了txtA的值,txtB和txtC就会自动改变,因为我已经为ValueA实现了INotifyPropertyChanged。

但他们没有在UI上更新。 txtB总是100,而txtC总是-50。

我不知道是什么原因。

我的Xaml ..

    <Window x:Class="WpfApplicationReviewDemo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <StackPanel>
            <TextBox Name="txtA" Text="{Binding ValueA}" />
            <TextBox Name="txtB" Text="{Binding ValueB}" />
            <TextBox Name="txtC" Text="{Binding ValueC}" />
        </StackPanel>
    </Window>

我的代码背后......

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        this.DataContext = new Model();
    }
}


public class Model : INotifyPropertyChanged
{
    private decimal valueA;
    public decimal ValueA { get {
        return valueA;
    }
        set
        {
            valueA = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ValueA"));
        }
    }

    private decimal valueB;
    public decimal ValueB
    {
        get
        {
            valueB = ValueA + 100;
            return valueB;
        }
        set
        {
            valueB = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ValueB"));
        }
    }


    private decimal valueC;
    public decimal ValueC
    {
        get
        {
            valueC = ValueA - 50;
            return valueC;
        }
        set
        {
            valueC = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ValueC"));
        }
    }


    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

在我将代码添加到ValueA属性的set方法之后,它可以正常工作。

    public decimal ValueA { get {
        return valueA;
    }
        set
        {
            valueA = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ValueA"));
            PropertyChanged(this, new PropertyChangedEventArgs("ValueB"));
            PropertyChanged(this, new PropertyChangedEventArgs("ValueC"));
        }
    }

但我认为应该为txtB和txtC自动刷新/更新。请指教。

4 个答案:

答案 0 :(得分:3)

我会这样做

public class Model : INotifyPropertyChanged
{
    private decimal valueA;

    public decimal ValueA
    {
        get { return valueA; }
        set
        {
            if( valueA != value )
            {
                valueA = value;
                PropertyChanged(this, new PropertyChangedEventArgs("ValueA"));
                PropertyChanged(this, new PropertyChangedEventArgs("ValueB"));
                PropertyChanged(this, new PropertyChangedEventArgs("ValueC"));
            }
        }
    }

    public decimal ValueB
    {
        get { return ValueA + 100; }
    }

    public decimal ValueC
    {
        get { return ValueA - 50; }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

public class Model2 : INotifyPropertyChanged
{
    private decimal valueA;
    private decimal valueB;
    private decimal valueC;

    public decimal ValueA
    {
        get { return valueA; }
        set
        {
            if( valueA != value )
            {
                valueA = value;
                PropertyChanged(this, new PropertyChangedEventArgs("ValueA"));

                ValueB = value + 100;
                ValueC = value - 50;
            }
        }
    }

    public decimal ValueB
    {
        get { return valueB; }
        private set
        {
            valueB = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ValueB"));
        }
    }

    public decimal ValueC
    {
        get { return valueC; }
        private set
        {
            valueC = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ValueC"));
        }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

答案 1 :(得分:1)

开箱即用,它不知道物业B&amp; C依赖于A.你需要告诉它你已经完成了。

答案 2 :(得分:1)

PropertyChanged允许任何数据绑定到属性已更改的对象。更改文本框的值时,请遵循代码的逻辑。为ValueA调用set方法,并将valueA设置为value。

set
{
    valueA = value;
    PropertyChanged(this, new PropertyChangedEventArgs("ValueA"));
}

然而,当调用PropertyChanged时,它所做的只是让TextBox知道值已经改变(它已经知道了,因为它调用了set方法)。另一个第二组方法的作用是它通知其他TextBox,它们的属性也发生了变化,所以它们需要反映这些变化。

set
{
    valueA = value;
    PropertyChanged(this, new PropertyChangedEventArgs("ValueA"));
    PropertyChanged(this, new PropertyChangedEventArgs("ValueB"));
    PropertyChanged(this, new PropertyChangedEventArgs("ValueC"));
}

这使得所有三个TextBox都可以更新显示以显示新值。

答案 3 :(得分:0)

您正在谈论的场景通常被称为“计算”或“计算”属性。但是,通常建议将它们设为只读。只读计算简化了代码,意味着您不需要有支持字段来存储值。

正如您已经解决的那样,INotifyPropertyChanged不会“自动”检测这些依赖关系。您需要根据依赖项显式触发事件。

这实际上是使用ILWeaving的完美案例。原因是在编译时ILWeaving可以检测到这些依赖关系并正确地触发多个事件。

例如,如果您使用NotifyPropertyWeaver http://code.google.com/p/notifypropertyweaver/,则可以像这样编写代码。

public class Model : INotifyPropertyChanged
{
    public decimal ValueA { get; set; }

    public decimal ValueB
    {
        get { return ValueA + 100;}
    }

    public decimal ValueC
    {
        get { return ValueA - 50; }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

并编译了这个

public class Model : INotifyPropertyChanged
{
    public virtual void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    decimal valueA;

    public decimal ValueA
    {
        get { return valueA; }
        set
        {
            if (!decimal.Equals(valueA, value))
            {
                valueA = value;
                OnPropertyChanged("ValueB");
                OnPropertyChanged("ValueC");
                OnPropertyChanged("ValueA");
            }
        }
    }

    public decimal ValueB
    {
        get { return ValueA + 100;}
    }

    public decimal ValueC
    {
        get { return ValueA - 50; }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

请注意,OnPropertyChanged方法已经与三个调用一起注入了“A”的setter中。

请注意,“B”和“C”文本框也应该是只读的

    <TextBox Name="txtA" Text="{Binding ValueA}" />
    <TextBox Name="txtB" Text="{Binding ValueB}" IsReadOnly="True" />
    <TextBox Name="txtC" Text="{Binding ValueC}" IsReadOnly="True" />