105

I am trying to bind to an integer property:

<RadioButton Content="None"
             IsChecked="{Binding MyProperty,
                         Converter={StaticResource IntToBoolConverter},
                         ConverterParameter=0}" />

and my converter is:

[ValueConversion(typeof(int), typeof(bool))]
public class IntToBoolConverter : IValueConverter
{
    public object Convert(object value, Type t, object parameter, CultureInfo culture)
    {
        return value.Equals(parameter);
    }

    public object ConvertBack(object value, Type t, object parameter, CultureInfo culture)
    {
        return value.Equals(false) ? DependencyProperty.UnsetValue : parameter;
    }
}

the problem is that when my converter is called the parameter is string. i need it to be an integer. of course i can parse the string, but do i have to?

thanks for any help konstantin

Taterhead
  • 5,763
  • 4
  • 31
  • 40
akonsu
  • 28,824
  • 33
  • 119
  • 194
  • 2
    Does anybody know how to achive this on Windows Phone platform where we have slightly different syntax for bindings? {Binding PROPERTY, Converter={StaticResource MYCONVERTER}, ConverterParameter=INT_VAL} in this example INT_VAL will be passed as a string – Krzysztof Kaczor Nov 11 '13 at 20:56

5 Answers5

129

Here ya go!

<RadioButton Content="None"
             xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <RadioButton.IsChecked>
        <Binding Path="MyProperty"
                 Converter="{StaticResource IntToBoolConverter}">
            <Binding.ConverterParameter>
                <sys:Int32>0</sys:Int32>
            </Binding.ConverterParameter>
        </Binding>
    </RadioButton.IsChecked>
</RadioButton>

The trick is to include the namespace for the basic system types and then to write at least the ConverterParameter binding in element form.

jpierson
  • 16,435
  • 14
  • 105
  • 149
  • 2
    This doesn't change the fact that the type of `IValueConverter.Convert()`'s *"parameter"* parameter is `object`. You still have to cast/parse it... – Dan J Aug 02 '11 at 16:11
  • 6
    @djacobson - True but that is what the ValueConversion attribute allows you to specify. Not exactly sure whether this is really used by at compile-time or run-time at all. In terms of the original posters question he specified that "i need it to be an integer. of course i can parse the string, but do i have to?" So my answer alleviates that in that there is no parsing of a string but only the unboxing of an integer which I is still much more safe. – jpierson Aug 04 '11 at 16:20
62

For completeness, one more possible solution (perhaps with less typing):

<Window
    xmlns:sys="clr-namespace:System;assembly=mscorlib" ...>
    <Window.Resources>
        <sys:Int32 x:Key="IntZero">0</sys:Int32>
    </Window.Resources>

    <RadioButton Content="None"
                 IsChecked="{Binding MyProperty,
                                     Converter={StaticResource IntToBoolConverter},
                                     ConverterParameter={StaticResource IntZero}}" />

(Of course, Window can be replaced with UserControl, and IntZero may be defined closer to the place of actual usage.)

Vlad
  • 35,022
  • 6
  • 77
  • 199
57

Not sure why WPF folks tend to be disinclined towards using MarkupExtension. It is the perfect solution for many problems including the issue mentioned here.

public sealed class Int32Extension : MarkupExtension
{
    public Int32Extension(int value) { this.Value = value; }
    public int Value { get; set; }
    public override Object ProvideValue(IServiceProvider sp) { return Value; }
};

If this markup extension is defined in XAML namespace 'local:', then the original poster's example becomes:

<RadioButton Content="None"
             IsChecked="{Binding MyProperty,
                         Converter={StaticResource IntToBoolConverter},
                         ConverterParameter={local:Int32 0}}" />

This works because the markup extension parser can see the strong type of the constructor argument and convert accordingly, whereas Binding's ConverterParameter argument is (less-informatively) Object-typed.

Glenn Slayden
  • 17,543
  • 3
  • 114
  • 108
  • Thanks, that was useful. It will be my first XAML extension. But I think it's better to make `Value` an `object` rather than `int`, to avoid boxing it each time in `ProvideValue`. (And then, make it `private` to avoid assigning something illegal directly). – Zeus Feb 05 '16 at 05:26
  • 1
    @Zeus Typically `ProvideValue` is only called once per markup extension instance, so the boxing should only occur once anyway. By not doing it in the constructor, I avoid boxing altogether if `ProvideValue` is never called. As for making `Value` private, this would preclude using the markup extension in `XAML` object element syntax: https://msdn.microsoft.com/en-us/library/ms788723(v=vs.100).aspx#object_element_syntax – Glenn Slayden Jun 19 '16 at 19:40
  • Your last paragraph is wrong. It's called type conversion and it also applies to properties. The thing is, that `Binding.ConverterParameter` has no specific type (it's just an `object`) so the parser does not know what conversion to apply, hence every literal is just treated as a string. – H.B. Aug 08 '16 at 13:39
  • (So if you extension had a default constructor, then `{m:Int32 Value=0}` would work just as well.) – H.B. Aug 08 '16 at 13:41
4

Don't use value.Equals. Use:

  Convert.ToInt32(value) == Convert.ToInt32(parameter)
Aliostad
  • 80,612
  • 21
  • 160
  • 208
0

It would be nice to somehow express the type information for the ConverterValue in XAML, but I don't think it is possible as of now. So I guess you have to parse the Converter Object to your expected type by some custom logic. I don't see another way.

SKG
  • 1,432
  • 2
  • 13
  • 23