Implement IMultiValueConverter to convert between blocks

I am working on a billing system and am using a DataGrid to input an item. I want users to be able to enter quantities in different units (for example, inches, feet, meters) and for this quantity entered, which should be converted to units of stock items. My first thought was to implement IMultiValueConverter , but I tried it from yesterday and can't figure it out.

My conversion method works exactly, I actually took the body, stuck it in another method and tested its output. My program crashes in the ConvertBack method, I am new to C # and I have never seen anyone really implement this method, so I wonder why this makes me implement it (I assume this is because my number is binding not included), but I really need the converted value to return to the original resource of the objects.

I really have no problem implementing the ConvertBack method, but the value parameter that is passed to the method is the value entered by the user and not the converted value, why is this so? If this is not a converted value, for this reason I cannot figure out how to go back, because I only have access to what the user enters, and not the desired units in this method.

I understand that my understanding of converters is probably far away, but if someone can help me understand where my thoughts are here, I would appreciate it, as well as any possible workarounds / solutions to my problem.

Thanks in advance!

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> 

<strong> 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 eg "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 } 
+4
source share
2 answers

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

You may have flipped Convert and ConvertBack :

Convert : converts a value from your model to a binding source (your data grid)

ConvertBack : Convert user input to model

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

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

Here is the MSDN documentation

UPDATE: So, I found my converter, and the memories came back. I ran into the same problem you just dealt with: how to pass the required units to the return return function. Honestly, I am not 100% satisfied with my decision, but I will share it with you.

Most of the ValueConverter implementations I've seen are stateless, so you can use them as a StaticResource for multiple bindings. I added a units field to my implementation to track units that sacrifice their 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 need to create a converter for each binding you use:

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

I would like to see a better solution to the problem, but it worked for me.

+7
source

I came across this message while trying to debug my own unit converter, which used a similar technique for Gene C to β€œremember” what units were in order to convert back. In my case, I convert angles (RADIANS, DEGREES) and distances (NATIVE_DIST, MM, INCHES). Things worked great most of the time, but in other cases the conversion would be completely wrong.

It turns out that value converters are shared by default. This means that "_units" in the Gene example will be set to all units that were used in the last call to "Convert". In my case, if I converted the distance from NATIVE_DIST-> MM (remembering that the original units were "NATIVE_DIST"), and then immediately called "ConvertBack" for another control related to the angle, the "remembered" units would be " NATIVE_DIST "" instead of the angle units that I had in mind.

The solution was to change the .xaml declaration for the converter:

 Change this <local:UnitsConverter x:Key="UnitsConverter"/> To this <local:UnitsConverter x:Key="UnitsConverter" x:Shared="false"/> 
+4
source

All Articles