WPF XAML 绑定中的自动字段更新 - 简单示例不起作用
Posted
技术标签:
【中文标题】WPF XAML 绑定中的自动字段更新 - 简单示例不起作用【英文标题】:Automatic field update in WPF XAML binding - simple example not working 【发布时间】:2021-12-09 18:06:17 【问题描述】:我是 C#、WPF、XAML 和绑定方面的新手,为了学习这个良好的环境,我自己创建了这个小练习:我想显示一个包含增值税和不包含增值税的价格。但是我希望在更改字段后立即自动更新另一个字段(所以只要我点击 Tab)。 我已经创建了一个类(感谢我在 Stack Overflow 中发布的另一个问题的帮助)来进行数学计算。但是我现在的问题是这些字段没有得到更新。我使用 INotifyPropertyChange 接口,但由于某种原因,它不起作用。 以下是正在发生的事情:
我使用以下 XAML 代码:
<Window x:Class="BTWv2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BTWv2"
mc:Ignorable="d"
Title="MainWindow" Height="150" Width="250">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Label Grid.Column="1" Grid.Row="1" Content="Amount inc VAT:" VerticalAlignment="Center" HorizontalAlignment="Center"/>
<TextBox
Grid.Column="2" Grid.Row="1"
VerticalAlignment="Center" HorizontalAlignment="Center"
Width="100" Text="Binding IncludeVat,Mode=TwoWay"/>
<Label Grid.Column="1" Grid.Row="3" Content="Amount excl VAT:" VerticalAlignment="Center" HorizontalAlignment="Center"/>
<TextBox Text="Binding ExcludeVat,Mode=TwoWay"
Grid.Column="2" Grid.Row="3"
VerticalAlignment="Center" HorizontalAlignment="Center"
MinWidth="100"
/>
</Grid>
</Window>
这是实际的 C# 代码(我正在使用一个名为 CalculateVAT 的类来计算数字:
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace BTWv2
public partial class MainWindow : Window
public MainWindow()
InitializeComponent();
CalculateVAT Price = new CalculateVAT();
Price.IncludeVat = 100;
DataContext = Price;
public class CalculateVAT : INotifyPropertyChanged
private decimal m_IncludeVat; // <- decimal is a better choice for finance
// To compute VAT we should know the percent; let it be known
public const decimal Percent = 21.0m;
public decimal IncludeVat
get => m_IncludeVat;
set
// negative cash are usually invalid; if it's not the case, drop this check
if (value < 0)
throw new ArgumentOutOfRangeException(nameof(value));
m_IncludeVat = value;
Tax = Math.Round(m_IncludeVat / 100 * Percent, 2);
NotifyPropertyChanged();
public decimal ExcludeVat
get => m_IncludeVat - Tax;
set
if (value < 0)
throw new ArgumentOutOfRangeException(nameof(value));
m_IncludeVat = Math.Round(value / 100 * (100 + Percent), 2);
Tax = m_IncludeVat - value;
NotifyPropertyChanged();
// Let's be nice and provide Tax value as well as IncludeVat, ExcludeVat
public decimal Tax get; private set;
public override string ToString() =>
$"Include: IncludeVat:f2; exclude: ExcludeVat:f2 (tax: Tax:f2)";
public event PropertyChangedEventHandler? PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
有人知道我在这里缺少什么吗? 我已经在绑定中尝试了 UpdateSourceTrigger=PropertyChanged 设置,但这似乎并没有改变任何东西..
【问题讨论】:
默认情况下,当控件失去焦点时会更新 xaml 绑定,...您可以通过指定 UpdateSourceTrigger 来更改该行为。对于您的示例: Text="Binding IncludeVat,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged" "默认情况下,当控件失去焦点时会更新 xaml 绑定" - true,但仅适用于 TextBox 的 Text 属性。当目标属性更改时,所有其他绑定都会更新其源属性。另请注意,Text 属性默认绑定 TwoWay。显式设置Mode=TwoWay
是多余的。
我已经尝试过 UpdateSourceTrigger=PropertyChanged 设置,但这似乎并没有改变任何东西......
@Tjerk 好的,还有一件事。 UpdateSourceTrigger 告诉 wpf 绑定系统何时将新值推回视图模型。现在您已设置含增值税的价格,但您必须通知不含增值税的价格已更改。只需调用 NotifyPropertyChanged(nameof(ExcludeVat));在 IncludeVat 属性设置器的末尾。
为了通知多个同时发生的属性更改,您可以使用空或 null PropertyName 触发一次 PropertyChanged 事件。这会将所有绑定通知到源对象的所有属性。
【参考方案1】:
假设您想在从 UI 更改 IncludeVat 时更新 ExcludeVat。 您需要在 IncludeVat 的 setter 中为这两个属性提高 notify 属性。
public decimal IncludeVat
get => m_IncludeVat;
set
// negative cash are usually invalid; if it's not the case, drop this check
if (value < 0)
throw new ArgumentOutOfRangeException(nameof(value));
m_IncludeVat = value;
Tax = Math.Round(m_IncludeVat / 100 * Percent, 2);
NotifyPropertyChanged(nameof(IncludeVat));
NotifyPropertyChanged(nameof(ExcludeVat));
这将做的是,当您从 UI 更改 IncludeVat 时,setter 现在会引发为 ExcludeVat 更改的属性。 UI 将尝试通过调用 ExcludeVat 的 getter 来更新。你是 ExcludeVat 的吸气剂:get => m_IncludeVat - Tax;现在将获得更新后的值,并且 UI 将反映这一点。
【讨论】:
以上是关于WPF XAML 绑定中的自动字段更新 - 简单示例不起作用的主要内容,如果未能解决你的问题,请参考以下文章
如何自动更新 WPF DataGrid 和 xml 之间的绑定