WPF绑定计算值

时间:2018-09-23 09:59:21

标签: wpf

我试图了解ValueConverters的工作原理。我有三个分别为 txtQty txtPrice txtAmount 的文本框,分别表示数量,价格和金额,金额=数量x价格。

txtQty和txtPrice是未绑定的控件,将txtAmount绑定到数据集中的数据表

如何使用ValueConveter(将txtQty和txtPrice作为输入值)更新绑定到DataTable的txtAmount中的值?

我可以通过多种方式轻松实现这一目标。 但是我想为此使用ValueConverter

有什么想法吗?

1 个答案:

答案 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

希望这会有所帮助。

enter image description here