C# 具有只读属性的数据绑定

C# 具有只读属性的数据绑定,c#,xaml,data-binding,uwp,C#,Xaml,Data Binding,Uwp,我有一个视图,允许用户输入支付金额,然后选择输入本金、利息和托管金额 这四个TextBoxes使用two-way数据绑定,一切都很好,如下所示: <TextBlock Grid.Row="3" Grid.Column="0" Text="Payment Amount" /> <TextBox Grid.Row="3" Grid.Column="1" Text="{x:Bind ViewModel.C

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

这四个
TextBox
es使用
two-way
数据绑定,一切都很好,如下所示:

<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
正确显示,但在值更改时不会更新。以下是
文本块的XAML:

<TextBlock Text="{x:Bind ViewModel.CurrentPayment.TotalAmount, Converter={StaticResource StringFormatConverter}, ConverterParameter='{}{0:N}'}" />
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);
}
公共抽象类BindableBase:IBindable,INotifyPropertyChanged
{
受保护的BindableBase();
公共事件属性更改事件处理程序属性更改;
公共虚拟void RaisePropertyChanged([CallerMemberName]字符串propertyName=null);
公共虚拟无效RaisePropertyChanged(表达式属性Expression);
公共虚拟布尔集合(ref T storage,T value,[CallerMemberName]string propertyName=null);
公共虚拟布尔集合(表达式属性Expression,ref T字段,T newValue);
}
编辑

我遇到的主要问题是由于编译绑定的不同行为。默认的
模式
OneTime
,这与标准的
单向绑定默认模式
不同。一旦我将属性更改通知提升到
TotalValue
属性,我仍然必须将绑定模式更改为
OneWay
,以更新我的UI

有关标准绑定和编译绑定的更多信息,请访问

是的,当这三个属性中的一个发生更改时,您的模型类(付款)应实现并引发属性的
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
。这就是我总是显式设置绑定模式的原因。:)它也欺骗了我,因为我以前曾尝试显式地将绑定设置为单向
,但那是在我按照您的回答中的建议添加了
RaisePropertyChanged
之前。请参见,在您的示例中,当设置其他三个属性之一时,不会通知属性
TotalAmount
,因此,UI不会更新。;)我是否应该在每个setter中添加一个通知,以通知
TotalAmount
?是的,就像我在回答中告诉您的那样。这是不同的。您的答案显示
PrincipalAmount
PrincipalAmount
上引发属性更改事件。我的属性已在更新时发出通知(在
Set()中)
模板10的
BindableBase
对不起,我的错,这就是我的意思,我更正了我的答案。它应该更新
TotalAmount
,就像现在一样。
PrincipalAmount
当然是由您设置的方法自动通知的。我被您的属性名称分散了注意力。
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);
}
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));
        }
    }
}