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



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

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 属性的设置方法后,它可以工作。

    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 自动刷新/更新。请指教。

我会这样处理

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
}

开箱即用,它不知道属性B和C依赖于A。你需要像你所做的那样告诉它。

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

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

但是,当调用 PropertyChanged 时,它所做的只是让 TextBox 知道值已更改(它已经知道,因为它调用了 set 方法)。另一个第二个 set 方法工作的原因是,它通知其他 TextBox 其属性也已更改,因此它们需要反映更改。

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

这允许所有三个文本框更新显示以显示新值。

您正在谈论的方案通常称为"计算"或"计算"属性。但是,通常建议将它们设置为只读。只读计算简化了代码,意味着无需支持字段来存储值。

正如您已经计算的那样,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" />

相关内容

  • 没有找到相关文章

最新更新