【问题标题】:DataBinding with read-only property具有只读属性的数据绑定
【发布时间】:2017-02-20 22:51:50
【问题描述】:

我有一个视图允许用户输入付款金额,然后可选择输入本金、利息和托管金额。

这四个 TextBoxes 使用 TwoWay 数据绑定一切都很好,如下所示:

<TextBlock Grid.Row="3"
           Grid.Column="0"
           Text="Payment Amount" />
<TextBox Grid.Row="3"
         Grid.Column="1"
         Text="{x:Bind ViewModel.CurrentPayment.PaymentAmount, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:N}', Mode=TwoWay}" />
<TextBlock Grid.Row="4"
           Grid.Column="0"
           Text="Principal" />
<TextBox Grid.Row="4"
         Grid.Column="1"
         Width="100" Text="{x:Bind ViewModel.CurrentPayment.PrincipalAmount, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:N}', Mode=TwoWay}" />
<TextBlock Grid.Row="5"
           Grid.Column="0"
           Text="Interest" />
<TextBox Grid.Row="5"
         Grid.Column="1"
         Width="100"
         MaxLength="20"
         Text="{x:Bind ViewModel.CurrentPayment.InterestAmount, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:N}', Mode=TwoWay}" />
<TextBlock Grid.Row="6"
           Grid.Column="0"
           Text="Escrow" />
<TextBox Grid.Row="6"
         Grid.Column="1"
         Width="100"
         MaxLength="20"
         Text="{x:Bind ViewModel.CurrentPayment.EscrowAmount, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:N}', Mode=TwoWay}" />

但是,当我尝试添加一个名为 TotalAmount 的“汇总”属性时,它会占用 PrincipalAmount+InterestAmount+EscrowAmount 的总数,如下所示:

[JsonIgnore]
public decimal TotalAmount
{
    get
    {
        var amount = EscrowAmount + InterestAmount + PrincipalAmount;
        return amount;
    }
}

如果用户更改本金/利息/托管金额的TextBox,我的财产不会更新。 TotalAmount 在加载视图时正确显示,但在值更改时不会更新。这是TextBlock 的 XAML:

<TextBlock Text="{x:Bind ViewModel.CurrentPayment.TotalAmount, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:N}'}" />

有没有办法让TotalAmount 属性知道其他属性的值何时发生变化,以便它可以更新显示的值?

编辑

添加其他三个属性定义以显示 INotifyPropertyChanged 的使用。

private decimal _principalAmount;
[JsonProperty("principalamount")]
public decimal PrincipalAmount
{
    get { return _principalAmount; }
    set { Set(ref _principalAmount, value); }
}

private decimal _escrowAmount;
[JsonProperty("escrowamount")]
public decimal EscrowAmount
{
    get { return _escrowAmount; }
    set { Set(ref _escrowAmount, value); }
}

private decimal _interestAmount;
[JsonProperty("interestamount")]
public decimal InterestAmount
{
    get { return _interestAmount; }
    set { Set(ref _interestAmount, value); }
}

Set 是模板 10 的 BindableBase 中的一个方法:

public abstract class BindableBase : IBindable, INotifyPropertyChanged
{
    protected BindableBase();

    public event PropertyChangedEventHandler PropertyChanged;

    public virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null);
    public virtual void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression);
    public virtual bool Set<T>(ref T storage, T value, [CallerMemberName] string propertyName = null);
    public virtual bool Set<T>(Expression<Func<T>> propertyExpression, ref T field, T newValue);
}

编辑

我遇到的主要问题是编译绑定的不同行为。默认ModeOneTime,与标准绑定默认OneWay不同。将属性更改通知提升到 TotalValue 属性后,我仍然必须将绑定模式更改为 OneWay 才能更新我的 UI。

有关标准绑定和编译绑定的更多信息,请访问x:Bind markup extension

【问题讨论】:

  • 请参阅,在您的示例中,当设置其他三个属性之一时,不会通知属性 TotalAmount,因此不会更新 UI。 ;)
  • 是否应该在每个setter中添加一个通知来通知TotalAmount??
  • 是的,就像我在回答中告诉你的那样。
  • 那是不同的。您的答案显示PrincipalAmountPrincipalAmount 上引发属性更改事件。我的属性在更新时已经通知(在模板 10 的 BindableBase 中的 Set() 方法内@
  • 对不起,我的错,这就是我的意思,我更正了我的答案。它应该像现在一样更新TotalAmountPrincipalAmount 当然会由您的 Set 方法自动通知。我被你的财产名称分心了。

标签: c# xaml data-binding uwp


【解决方案1】:

是的,当这三个属性之一发生更改时,您的模型类(付款)应该实现 INotifyPropertyChanged 并为属性 TotalAmount 引发 PropertyChanged 事件。

并确保在设置新值后为TotalAmount 提高PropertyChanged,否则它不会使用最新值更新TotalAmount,这可能不是你想要的。

例子:

Payment : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(string propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private decimal _principalAmount;
    public decimal PrincipalAmount
    {
        get { return _principalAmount; }
        set
        {
            _principalAmount = value;
            NotifyPropertyChanged(nameof(PrincipalAmount));

            // lets the design know that property "TotalAmount" should also be updated ...
            NotifyPropertyChanged(nameof(TotalAmount));
        }
    }
}

【讨论】:

  • 其他三个属性都实现了INotifyPropertyChanged。我假设当其中一个发生更改时,他们会更新TotalAmount 属性。我会将其他三个属性添加到我的问题中。
  • INotifyPropertyChanged 应该实现模型类,而不是属性类。看看我上面的例子。
  • 除了RaisePropertyChanged,我还必须添加设置Mode=OneWay。显然x:Bind 的默认值默认为Mode=OneTime
  • 我明白了。这就是为什么我总是明确设置绑定模式。 :)
  • 它也欺骗了我,因为我之前曾尝试将绑定显式设置为 OneWay,但那是在我按照您在回答中建议的那样添加 RaisePropertyChanged 之前。
猜你喜欢
  • 2010-11-19
  • 2012-12-19
  • 1970-01-01
  • 2020-04-25
  • 2010-10-14
  • 1970-01-01
  • 1970-01-01
  • 2011-01-30
  • 2013-12-12
相关资源
最近更新 更多