WPF XAML 绑定中的自动字段更新 - 简单示例不起作用
Automatic field update in WPF XAML binding - simple example not working
我是 C#、WPF、XAML 和绑定的新手,为了学习这个不错的环境,我自己创建了这个小练习:我想显示包含增值税和不含增值税的价格。但是我想让另一个字段在我更改字段后立即自动更新(所以只要我点击 Tab)。
我已经创建了一个 class(感谢我在 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 的 class 来计算数字:
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 设置,但这似乎没有任何改变..
假设您想在从 UI 更改 IncludeVat 时更新 ExcludeVat。
您需要为 IncludeVat 的 setter 中的两个属性提出通知 属性 已更改。
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 进行更新。您 getter 的 ExcludeVat :获取 => m_IncludeVat - 税;现在将获得更新后的值,UI 将反映出来。
我是 C#、WPF、XAML 和绑定的新手,为了学习这个不错的环境,我自己创建了这个小练习:我想显示包含增值税和不含增值税的价格。但是我想让另一个字段在我更改字段后立即自动更新(所以只要我点击 Tab)。 我已经创建了一个 class(感谢我在 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 的 class 来计算数字:
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 设置,但这似乎没有任何改变..
假设您想在从 UI 更改 IncludeVat 时更新 ExcludeVat。 您需要为 IncludeVat 的 setter 中的两个属性提出通知 属性 已更改。
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 进行更新。您 getter 的 ExcludeVat :获取 => m_IncludeVat - 税;现在将获得更新后的值,UI 将反映出来。