我试图了解ValueConverters的工作原理。我有三个分别为 txtQty , txtPrice 和 txtAmount 的文本框,分别表示数量,价格和金额,金额=数量x价格。
txtQty和txtPrice是未绑定的控件,将txtAmount绑定到数据集中的数据表。
如何使用ValueConveter(将txtQty和txtPrice作为输入值)更新绑定到DataTable的txtAmount中的值?
我可以通过多种方式轻松实现这一目标。 但是我想为此使用ValueConverter 。
有什么想法吗?
答案 0 :(得分:0)
您可以创建一个转换器,该转换器实现 IMultiValueConverter 以计算您的价格和数量。
public class AmountConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
decimal qty = 0;
decimal price = 0;
if (values?.Length < 2)
throw new ArgumentNullException("Parameter should contain 2 values");
if (!string.IsNullOrEmpty(values[0].ToString()) && !decimal.TryParse(values[0].ToString(), out qty))
throw new ArgumentException("1st value should be decimal.");
if (!string.IsNullOrEmpty(values[1].ToString()) && !decimal.TryParse(values[1].ToString(), out price))
throw new ArgumentException("2nd value should be decimal.");
return (qty * price).ToString();
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
然后将 MultiBinding 用于“金额”文本框
<TextBox x:Name="txtAmount" HorizontalAlignment="Left" IsReadOnly="True">
<TextBox.Text>
<MultiBinding Converter="{StaticResource AmountConverter}">
<Binding ElementName="txtQty" Path="Text" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
<Binding ElementName="txtPrice" Path="Text" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
但是,您可能需要与txtQty和txtPrice进行一些交互操作以更新绑定到viewmodel的Amount,您可能还需要从vm调用命令来完成此操作。
列出整个测试xaml和viewmodel代码...
<Window x:Class="WpfApp2.MainWindow"
x:Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:interactivity="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp2"
xmlns:vm="clr-namespace:WpfApp2.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<vm:ViewModelTest />
</Window.DataContext>
<Window.Resources>
<local:AmountConverter x:Key="AmountConverter" />
</Window.Resources>
<Grid Margin="12 0 0 0" >
<StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock HorizontalAlignment="Left" Text="Qty" Margin="0 0 12 0" />
<TextBox x:Name="txtQty" HorizontalAlignment="Left" Height="20" Width="50" >
<interactivity:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding DataContext.UpdateAmountCommand, ElementName=root}" CommandParameter="{Binding Path=Text, ElementName=txtAmount}" />
</i:EventTrigger>
</interactivity:Interaction.Triggers>
</TextBox>
</StackPanel>
<StackPanel Orientation="Vertical" >
<TextBlock HorizontalAlignment="Left" Text="Price" Margin="0 0 12 0" />
<TextBox x:Name="txtPrice" HorizontalAlignment="Left" Height="20" Width="50" >
<interactivity:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding DataContext.UpdateAmountCommand, ElementName=root}" CommandParameter="{Binding Path=Text, ElementName=txtAmount}" />
</i:EventTrigger>
</interactivity:Interaction.Triggers>
</TextBox>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock HorizontalAlignment="Left" Text="Amount" Margin="0 0 12 0" />
<TextBox x:Name="txtAmount" HorizontalAlignment="Left" IsReadOnly="True">
<TextBox.Text>
<MultiBinding Converter="{StaticResource AmountConverter}">
<Binding ElementName="txtQty" Path="Text" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
<Binding ElementName="txtPrice" Path="Text" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
</StackPanel>
</StackPanel>
</Grid>
</Window>
VM
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace WpfApp2.ViewModel
{
public class ViewModelTest : INotifyPropertyChanged
{
public ViewModelTest()
{
UpdateAmountCommand = new CustomCommand<string>(UpdateAmount, (x) => true);
}
private decimal _amount;
public decimal Amount
{
get => _amount;
set
{
if (_amount != value)
{
_amount = value;
OnPropertyChanged();
}
}
}
public CustomCommand<string> UpdateAmountCommand { get; }
private void UpdateAmount(string amountText)
{
Amount = decimal.Parse(amountText);
Debug.WriteLine(Amount);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
不确定是否有更简单的方法,这只是我的脑袋。
PS:您可以复制 CustomCommand 实现here。
希望这会有所帮助。