System.Windows.Data.MultiBinding.Converter threw an exception - c#

trying to implement some code behind in my xaml document. The idea here is that the code behind will compare two values, and return True if they strings are equal, but i keep getting System.Windows.Data.MultiBinding.Converter threw an exception
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cvm="clr-namespace:Mashup;assembly=CompareValuesMashup"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
xmlns:dat="clr-namespace:System.Windows.Data;assembly=PresentationFramework"
xmlns:xlink="http://www.w3.org/1999/xlink">
<Grid.Resources>
<cvm:CompareTwoValues x:Key="CompareValues" />
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<StackPanel Width="200" HorizontalAlignment="Left" Margin="5">
<!-- values to be processed by the converter -->
<TextBox Name="value1" Height="50" Margin="0,0,0,0" />
<TextBox Name="value2" Height="50" Margin="0,15,0,0" />
<!-- Compare value1 and value2-->
<TextBox Name="result1" Height="50" Margin="0,15,0,0">
<TextBox.Text>
<MultiBinding Converter="{StaticResource CompareValues}">
<Binding ElementName="value1" Path="Text" />
<Binding ElementName="value2" Path="Text" />
</MultiBinding>
</TextBox.Text>
</TextBox>
</StackPanel>
</Grid>
here's the code behind. I'm not sure where the exception is coming from.
namespace Mashup
{
public class CompareTwoValues
{
public CompareTwoValues()
{
base..ctor();
}
public bool Execute(string value1, string value2)
{
return value1 == value2;
}
}
}

CompareTwoValues doesn't implement IMultiValueConverter. It doesn't implement any interface or base class, so I wouldn't expect it to be usable by the framework in similar scenarios either.
It needs to implement that interface to be used by the framework:
public class CompareTwoValues : IMultiValueConverter
{
public CompareTwoValues()
{
base..ctor();
}
public bool Execute(string value1, string value2)
{
return value1 == value2;
}
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
// convert the values to the target type
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
// convert the value back to the set of target types
}
}
Currently the class compares values, but it doesn't convert anything. It's not entirely clear from the existing class logic what that conversion would look like, but it needs to happen in order to be used in this context.
An example of converting multiple values to a single value might be something like:
return String.Concat(values[0], " ", values[1]);
And converting back might be something like:
return (value as string).Split(' ');
(If, for example, the values were strings and the desired result is a concatenated space-delimited string.)

Wouldn't it be much better to implement a single ValueConverter?
like this:
public class CompareValues: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == parameter;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and then use it
<!-- Compare value1 and value2-->
<TextBox Name="result1" Height="50" Margin="0,15,0,0">
<TextBox.Text>
<Binding Converter="{StaticResource CompareValues}" ElementName="value1" Path="Text">
<Binding.ConverterParameter>
<Binding Path="Text" ElementName="value2"/>
</Binding.ConverterParameter>
</MultiBinding>
</TextBox.Text>
</TextBox>

#david This worked or my purposes. I needed to return a string that i can use to trigger a style.
public class IsEqual : IMultiValueConverter
{
public object Convert(object[] values, Type targetTypes, object parameter, CultureInfo culture)
{
if (values[0] == "")
return string.Format("blank");
// returns yes if equal
else if (string.Equals(values[0], values[1]))
return string.Format("yes");
//returns no if not equal
else
return String.Format("no");
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}

Related

Multibinding generates "Cannot set MultiBinding because MultiValueConverter must be specified"

I have a button with binding which works fine, see below:
<Button x:Name="licenceFilterSet" Content="Search" Command="{Binding searchCommand}" CommandParameter="{Binding Path=Text, ElementName=licenseTextBox}" />
Now I have realized that I need yet another piece of information, so I need to send the value of a check-box as well.
I modified the VM like this:
<Button x:Name="licenceFilterSet" Content="Search" Command="{Binding licenseSearchCommand}">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource searchFilterConverter}">
<Binding Path="Text" ElementName="licenseTextBox" />
<Binding Path="IsEnabled" ElementName="regularExpressionCheckBox" />
</MultiBinding>
</Button.CommandParameter>
</Button>
Below is my multi-converter:
/// <summary>
/// Converter Used for combining license search textbox and checkbox
/// </summary>
public class SearchFilterConverter : IMultiValueConverter
{
public object Convert(object[] values)
{
return new Tuple<String, bool>((String)values[0], (bool)values[1]);
}
}
What am I doing wrong. I am getting the following error, (which is pointing to my MultiBinding-tag in XAML):
Cannot set MultiBinding because MultiValueConverter must be specified.
you have to implement IMultiConverter
public class SearchFilterConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return new Tuple<String, bool>((String)values[0], (bool)values[1]);;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
then create the resource in xaml
<Converter:SearchFilterConverter x:Key="searchFilterConverter" />
then it should work
<Button x:Name="licenceFilterSet" Content="Search" Command="{Binding licenseSearchCommand}">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource searchFilterConverter}">
<Binding Path="Text" ElementName="licenseTextBox" />
<Binding Path="IsEnabled" ElementName="regularExpressionCheckBox" />
</MultiBinding>
</Button.CommandParameter>
</Button>
I know this thread is old, but I've faced the same problem yesterday where everything was written correctly yet the WPF was still refusing to locate the converter. What helped me was assigning the converter in the following manner:
<MultiBinding Converter="{local:ButtonParametersMultiValueConverter}">
That solved the issue.
That is not the correct implementation of the IMultiValueConverter interface.
The correct one is:
public class SearchFilterConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
....
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
}
}
Reference here.

WPF CommandParameter MultiBinding values null

I am simply trying to bind two controls as command parameters and pass them into my command as an object[].
XAML:
<UserControl.Resources>
<C:MultiValueConverter x:Key="MultiParamConverter"></C:MultiValueConverter>
</UserControl.Resources>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<Button Name="Expander" Content="+" Width="25" Margin="4,0,4,0" Command="{Binding ExpanderCommand}">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource MultiParamConverter}">
<Binding ElementName="Content"/>
<Binding ElementName="Expander"/>
</MultiBinding>
</Button.CommandParameter>
</Button>
<Label FontWeight="Bold">GENERAL INFORMATION</Label>
</StackPanel>
<StackPanel Name="Content" Orientation="Vertical" Visibility="Collapsed">
<Label>Test</Label>
</StackPanel>
</StackPanel>
Command:
public ICommand ExpanderCommand
{
get
{
return new RelayCommand(delegate(object param)
{
var args = (object[])param;
var content = (UIElement)args[0];
var button = (Button)args[1];
content.Visibility = (content.Visibility == Visibility.Visible) ? Visibility.Collapsed : Visibility.Visible;
button.Content = (content.Visibility == Visibility.Visible) ? "-" : "+";
});
}
}
Converter:
public class MultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return values;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException("No two way conversion, one way binding only.");
}
}
Basically what is happening is that the binding seems to be working fine and the converter is returning an object[] containing the correct values, however when the command executes the param is an object[] containing the same number of elements except they are null.
Can someone please tell me why the values of the object[] parameter are being set to null?
Thanks,
Alex.
This'll do it:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values.ToArray();
}
Take a look at this question for the explanation.

Make converter for columnSpan

I would like to dynamic do the columnSpan on the userControl. I created the converter class, but it didn’t work. Would you show me how to do it correctly? Thanks.
The code on my UserControl:
<TextBlock x:Name="txtSumary" Grid.Row="0" Grid.Column="1" Text="{Binding summary}"
TextWrapping="Wrap" Style="{StaticResource PhoneTextAccentStyle}" Grid.ColumnSpan="{Binding isSpan, Converter={StaticResource ColumSpanConverter}}" />
It is reference on the UserControl.Resources
<local:VisibilityConverter x:Key="ColumSpanConverter"/>
There is the Converter Class:
public class ColumSpanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isSpan = (bool)value;
return isSpan ? 2 : 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
The converter is referencing the wrong converter:
<local:VisibilityConverter x:Key="ColumSpanConverter"/>
Should be:
<local:ColumSpanConverter x:Key="ColumSpanConverter" />

XAML can't find the converter class

I'm displaying a popup with the following code:
<Popup PlacementTarget="{Binding ElementName=categoryTagEditorControl}"
Placement="Bottom">
<Popup.IsOpen>
<MultiBinding Mode="OneWay" Converter="{StaticResource BooleanOrConverter}">
<Binding Mode="OneWay" ElementName="categoryTagEditorControl" Path="IsMouseOver"/>
<Binding RelativeSource="{RelativeSource Self}" Path="IsMouseOver" />
</MultiBinding>
</Popup.IsOpen>
<StackPanel>
<TextBox Text="Some Text.."/>
<DatePicker/>
</StackPanel>
</Popup>
Here's the code of BooleanOrConverter:
public class BooleanOrConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
foreach (object booleanValue in values)
{
if (booleanValue is bool == false)
{
throw new ApplicationException("BooleanOrConverter only accepts boolean as datatype");
}
if ((bool)booleanValue == true)
{
return true;
}
}
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
and its placed into PopupTest.InfoPanels.Windows namespace
when I run this, I'm getting following exception:
Cannot find resource named 'BooleanOrConverter'. Resource names are case sensitive.
What should I change for this to work?
It sounds like your Multibinding doesn't know where to look for the converter. Have you defined the converter as a staticresource? You can either specify the converter in the control's resources or in the included ResourceDictionary. Add a reference to the converter's namespace and then define a ResourceKey for it. Something like:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:MyConverters">
<UserControl.Resources>
<converters:BooleanOrConverter x:Key="BoolOrConverter"/>
</UserControl.Resources>
... // use converter as you were before
</UserControl>

Change Binding value in XAML

I need to make some complex binding in XAML. I have a DependencyProperty typeof(double); let's name it SomeProperty. Somewhere in XAML code of my control, I need to use the whole SomeProperty value, somewhere only a half, somewhere SomeProperty/3, and so on.
How can I do something like:
<SomeControl Value="{Binding ElementName=MyControl, Path=SomeProperty} / 3"/>
:)
Looking forward.
Use a division ValueConverter:
public class DivisionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int divideBy = int.Parse(parameter as string);
double input = (double)value;
return input / divideBy;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
<!-- Created as resource -->
<local:DivisionConverter x:Key="DivisionConverter"/>
<!-- Usage Example -->
<TextBlock Text="{Binding SomeProperty, Converter={StaticResource DivisionConverter}, ConverterParameter=1}"/>
<TextBlock Text="{Binding SomeProperty, Converter={StaticResource DivisionConverter}, ConverterParameter=2}"/>
<TextBlock Text="{Binding SomeProperty, Converter={StaticResource DivisionConverter}, ConverterParameter=3}"/>

Categories