实现IMultiValueConverter在单位之间进行转换 [英] implementing IMultiValueConverter to convert between units

查看:63
本文介绍了实现IMultiValueConverter在单位之间进行转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个发票系统,并且正在使用DataGrid进行项目输入.我希望用户能够以不同的单位(例如,英寸,英尺,米)输入数量,并将输入的数量转换为商品的库存单位.我最初的想法是实现IMultiValueConverter,但是从昨天开始我一直在尝试,无法弄清楚.

I'm working on an invoicing system, and am using a DataGrid for item entry. I want users to be able to enter the quantities in different units (e.g. inches, feet, meters) and for that entered quantity to be converted to the item's stocking units. My first thought was to implement an IMultiValueConverter, but I've been trying since yesterday and cannot figure it out.

我的Convert方法肯定可以正常工作,实际上我已经拿走了身体,将其卡在另一种方法中并测试了其输出.我的程序在ConvertBack方法中崩溃,我是C#的新手,我从未见过有人真正实现过该方法,所以我想知道为什么它强迫我实现它(我猜这是因为我的数量绑定不是单向的),但是我实际上需要转换后的值才能返回到源对象的Quantity属性.

My Convert method works for sure, I have actually taken the body, stuck it in another method and tested its output. My program is crashing in the ConvertBack method, I'm new to C# and I've never seen anyone actually implement that method, so I'm wondering why It's forcing me to implement it (I'm guessing it's because my Quantity binding is not oneway), but I actually need the converted value to go back to the source objects Quantity property.

实现ConvertBack方法确实没有问题,但是传递给该方法的value参数是用户输入的值,而不是转换后的值,为什么呢?如果不是转换后的值,出于这个原因,我无法真正弄清楚如何倒退,因为我只能访问用户输入的内容,而不能访问该方法中所需的单位.

I don't really have a problem implementing the ConvertBack method, but the value parameter that is passed to the method is the value the user entered, and not the converted value, why is that? Should it not be the converted value, for that reason I can't really figure out how to go backwards, because I only have access to what the user is entering, and not the desired units in that method.

我意识到我对转换器的理解可能还很遥远,但是如果有人可以帮助我理解我的想法在哪里,我将很感激于此,以及对我的问题的任何可能的解决方法/解决方案.

I realize my understanding of converters is probably way off, but if someone can help me understand where my thinkings off here, I'd appreciate that as well as any potential workarounds/solutions for my problem.

提前谢谢!

Pages/PurchaseInvoicePage.xaml

<DataGrid x:Name="ItemsGrid" Grid.Row="2" Grid.ColumnSpan="3" PreviewKeyDown="ItemsGrid_PreviewKeyDown" ItemsSource="{Binding Items}" FontSize="11" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" RowHeaderWidth="0" GridLinesVisibility="None" CanUserResizeRows="False" CanUserResizeColumns="False" CanUserReorderColumns="False">
    <DataGrid.Columns>

        <DataGridTemplateColumn x:Name="ItemNoColumn" Width="150" Header="Item No." IsReadOnly="True">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBox Cursor="Arrow" Width="130" BorderThickness="0" Background="Transparent" IsReadOnly="True" Text="{Binding Number}" />
                        <Image Cursor="Hand" MouseDown="ItemSelectionButton_Click" Width="12" Source="/Images/Icons/SearchBlack.png" />
                    </StackPanel>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <!-- question relative xaml starts here -->
        <DataGridTextColumn x:Name="QuantityColumn" Width="70" Header="Quantity">
            <DataGridTextColumn.Binding>
                <MultiBinding Converter="{StaticResource unitConverter}">
                    <Binding Path="Quantity" />
                    <Binding Path="Units" Mode="OneWay" />
                </MultiBinding>
            </DataGridTextColumn.Binding>
        </DataGridTextColumn>
        <!-- question relative xaml ends here -->

        <DataGridTextColumn x:Name="OrderColumn" Width="70" Header="Order" Binding="{Binding QuantityOrdered}" />
        <DataGridTextColumn x:Name="BackOrderColumn" Width="70" Header="B/O" Binding="{Binding QuantityBackOrdered}" />
        <DataGridTextColumn x:Name="UnitsColumn" Width="60" Header="Units" Binding="{Binding Units}" IsReadOnly="True" />
        <DataGridTextColumn x:Name="DescriptionColumn" Width="200" Header="Description" Binding="{Binding Description}" />
        <DataGridTextColumn x:Name="PriceColumn" Width="90" Header="Price" Binding="{Binding Price}" />
        <DataGridComboBoxColumn x:Name="TaxColumn" Width="50" Header="Tax" SelectedValueBinding="{Binding TaxCodeID}" DisplayMemberPath="Code" SelectedValuePath="ID" />
        <DataGridTextColumn x:Name="AmountColumn" Width="90" Header="Amount" Binding="{Binding Amount}" IsReadOnly="True" />
        <DataGridTextColumn x:Name="LinkedColumn" Width="90" Header="Linked" Binding="{Binding SalesOrderID}" />
    </DataGrid.Columns>
</DataGrid>

Fx/IMultiValueConverter.cs

public class UnitConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameters, CultureInfo culture)
    {
        double num = 0;
        // get the quantity value, and try parsing it
        string str = values[0].ToString().ToLower();
        bool parsed = double.TryParse(str, out num);

        // if it parses, no need to convert, return the value
        if (parsed)
            return num.ToString();

        // if it doesnt parse, get the last character in the value
        // this character indicates the units being entered
        // this will be either "(inches), f(eet), or m(eters) 
        string suffix = str.Substring(str.Length - 1);
        // get the value, without thhe last character
        str = str.Substring(0, str.Length - 1);
        // try parsing the value now
        parsed = double.TryParse(str, out num);

        // if it doesn't parse, the formats incorrect, return 0
        if (!parsed)
            return (0).ToString();

        // get the desired units, (the second value in my multibinding)
        string units = values[1].ToString().ToLower();

        // if either the entry suffix or the desired units are empty, just return
        // the number without converting
        if (string.IsNullOrEmpty(suffix) || string.IsNullOrEmpty(units))
            return num;

        // convert from inches to feet
        if (suffix == "\"" && units == "feet")
            return (num / 12).ToString();
        // convert from inches to meters
        else if (suffix == "\"" && units == "meters")
            return (num * 0.0254).ToString();
        // convert from feet to meters
        else if (suffix == "f" && units == "meters")
            return (num * 0.3048).ToString();
        // convert from meters to feet
        else if (suffix == "m" && units == "feet")
            return (num / 0.3048).ToString();

        // if we reachd this far, the user probably entered something random,
        // show an error and return 0
        MessageBox.Show("Failed to convert between the two units.");
        return (0).ToString();
    }

    public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
    {
        // now this is where my program is crashing, 
        // for some reason I need to actually implement the ConvertBack function
        // but when I try to popup the value being passed to this function,
        // it is the value the user entered e.g "20f" and not the converted value
        // should it not be the converted value? Why do I even need to implement this
        // how should i go backwards from here...
        string str = value.ToString();
        // MessageBox.Show(str);
        return new object[] { 0 }; // btw, I'm only returning one value, because the second binding is oneway

    }

推荐答案

有趣的是,几周前,我使用IMultiValueConverter实现了单位转换器.在我进行深入研究以查看是否可以为您提供帮助时,让我提出一个理论:

Funny, I implemented a unit converter using IMultiValueConverter just a few weeks ago. While I go dig it up to see if I can help you, Let me propose a theory:

也许您已经翻转了ConvertConvertBack:

Convert:将值从模型转换为绑定源(您的数据网格)

Convert: Converts the value from your model to the binding source (your data grid)

ConvertBack:将用户的输入转换为模型

ConvertBack: Converts the input from the user to the model

因此,您可以期望在ConvertBack函数的参数中提供用户输入.

So you can expect the user input to be provided in the parameters of the ConvertBack function.

现在让我看看是否可以找到该转换器...

Now let me see if I can find that converter...

此处是MSDN文档

更新:所以我找到了转换器,而记忆又涌回了.我遇到了刚刚遇到的相同问题:如何将所需的单位传递给逆转功能.老实说,我对解决方案并不满意,但我会与您分享.

UPDATE: So I found my converter, and the memories came rushing back. I encountered the same problem you just did: how would I pass the desired units to the convert back function. Honestly I am not 100% pleased with my solution, but I will share it with you.

我见过的ValueConverter的大多数实现都是无状态的,因此可以将它们用作StaticResource的多个绑定.我在实现中添加了一个单位字段以跟踪单位-这会牺牲其无状态性:

Most implementation of ValueConverter that I have seen are stateless, therefore you can use them as a StaticResource for multiple bindings. I added a units field to my implementation to keep track of the units - which sacrifices its statelessness:

public class UnitConverter : IMultiValueConverter
{
    private string _units;

    public object Convert(object[ ] values, Type targetType, object parameter, CultureInfo culture)
    {
         //Initialize
         _units = values[1];
         //Convert
    }

    public object Convert(object[ ] values, Type targetType, object parameter, CultureInfo culture)
    {
         //Use _units to convert back
    }
}

不幸的是,您必须为使用的每个绑定创建一个转换器:

Unfortunately, you have to create a converter for every binding that you use:

<DataGridTextColumn.Binding>
   <MultiBinding>
      <Binding Path="Quantity" />
      <Binding Path="Units" Mode="OneWay" />
      <MultiBinding.Converter>
         <yourNameSpace:UnitConverter/>
      </MultiBinding.Converter>
   </MultiBinding>
</DataGridTextColumn.Binding>

我很乐意为自己找到一个更好的解决方案,但这对我有用.

I would love to see a better solution myself to the problem, but this has worked for me.

这篇关于实现IMultiValueConverter在单位之间进行转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆