【问题标题】:WPF Binding Calculated ValuesWPF 绑定计算值
【发布时间】:2018-09-24 01:44:24
【问题描述】:

我正在尝试了解 ValueConverters 的工作原理。我有三个文本框,分别是 txtQtytxtPricetxtAmount,分别代表数量、价格和金额,金额 = 数量 x 价格。

txtQty 和 txtPrice 是未绑定的控件而 txtAmount 绑定到 DataSet 中的 DataTable

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

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

有什么想法吗?

【问题讨论】:

    标签: wpf


    【解决方案1】:

    您可以创建一个实现 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 作为 Amount 文本框

    <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-bound 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>
    

    虚拟机

    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

    希望这会有所帮助。

    【讨论】:

    • 感谢您的回复。问题是 txtAmount 是对 DataTable/Database 的绑定控件,而 txtQty 和 txtPrice 不是。如果我按照您的方式使用多重绑定,那么与 txtAmount 的数据库的绑定将被破坏。那是我的问题。
    • 我看到你没有做 mvvm。
    • 不,我不是。您的解决方案在我的情况下如何运作?
    猜你喜欢
    • 2011-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    • 2012-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多