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));
}
}
}