47

Is it possible to bind to a ConverterParameter in Silverlight 4.0?

For instance I would like to do something like this and bind the ConverterParameter to an object in a ViewModel for instance.

If this is not possible are there any other options?

<RadioButton
  Content="{Binding Path=Mode}"
  IsChecked="{Binding
    Converter={StaticResource ParameterModeToBoolConverter},
    ConverterParameter={Binding Path=DataContext.SelectedMode,ElementName=root}}"
/>
abatishchev
  • 92,232
  • 78
  • 284
  • 421
dparker
  • 1,084
  • 1
  • 9
  • 14

5 Answers5

57

Unfortunetly no, you can't bind to a ConverterParameter. There's two options I've used in the past: instead of using a Converter, create a property on your ViewModel (or whatever you're binding to) which does the conversion for you. If you still want to go the Converter route, pass the entire bound object to the converter and then you can do your calculation that way.

Joe McBride
  • 3,584
  • 2
  • 30
  • 36
  • 3
    Isn't there a way by having the converter inherit from `DependencyObject` etc.? I'm authoring a custom control, and I need to format the bound object according to another property in the control. – Shimmy Weitzhandler Feb 22 '12 at 21:43
  • 3
    What do you mean by "pass the entire bound object to the converter"? – Clément Nov 18 '12 at 00:16
  • Pass the object to the converter that has all of the properties needed for you to do your conversion. In the converter cast the passed in object to the specific type. – Joe McBride Nov 18 '12 at 06:01
  • 1
    If I'm passing the entire object to the converter, how can I implement `ConvertBack`? Recreate the initial object? Only possible if all the original properties are passed as `value` to `ConvertBack`. – Zev Spitz Jun 04 '13 at 17:00
  • 2
    same question as @Clément, I'd like to see how to bind the entire bound object (datacontext in my case). – Felix Oct 11 '14 at 03:05
21

Another option is to get fancy by creating a custom converter that wraps your other converter and passes in a converter param from a property. As long as this custom converter inherits DependencyObject and uses a DependencyProperty, it can be bound to. For example:

<c:ConverterParamHelper ConverterParam="{Binding ...}">

    <c:ConverterParamHelper.Converter>

        <c:RealConverter/>

    </c:ConverterParamHelper.Converter>

</c:ConverterParamHelper>
Tim Greenfield
  • 539
  • 5
  • 8
  • 1
    Is there an advantage to this approach over using a MultiBinding (http://www.switchonthecode.com/tutorials/wpf-tutorial-using-multibindings)? – Nathan Nov 27 '12 at 21:48
  • 1
    Can you post an implementation? – Zev Spitz Jun 04 '13 at 17:17
  • 2
    @Nathan I guess it's easier to implement `ConvertBack` with such a converter than with a MultiBinding. Consider a `TimeConverter` which converts a `DateTime` to a formatted time-only string. When using a `MultiBinding`, `ConvertBack` will only get the formatted string, which will not be enough to resolve the entire `DateTime`. Tim's converter allows passing a date via binding to `ConvertBack` as well. – Zev Spitz Jun 04 '13 at 17:25
  • @TimGreenfield Could you also show an example of how to use this? – Zev Spitz Jun 06 '13 at 09:24
  • Hi Tim, I'd love to try this, but I need more context and info than what's shown above. Can you please include all the necessary parts to set this up? What does the source of the ConverterParamHelper look like? The RealConverter would exist, not alone, but in the context of an element that includes the control being bound to, etc. Showing more of the context in a semi-realistic example would be extremely helpful because I can't seem to get this approach to work. – MylesRip Sep 05 '14 at 01:46
  • -1 : Hey Tim, the converter parameter is part of the binding, not the control itself. But the binding object is not part of the UI element tree and does not have any DataContext. I pretty sure your solution could not work. I tries it for many hours without success. – Eric Ouellet Aug 26 '15 at 15:13
18

I know it's an old question but maybe this will be useful to somebody who came across it. The solution I found is as follow:

public class WattHoursConverter : FrameworkElement, IValueConverter
    {

        #region Unit (DependencyProperty)

        /// <summary>
        /// A description of the property.
        /// </summary>
        public string Unit
        {
            get { return (string)GetValue(UnitProperty); }
            set { SetValue(UnitProperty, value); }
        }
        public static readonly DependencyProperty UnitProperty =
            DependencyProperty.Register("Unit", typeof(string), typeof(WattHoursConverter),
            new PropertyMetadata("", new PropertyChangedCallback(OnUnitChanged)));

        private static void OnUnitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((WattHoursConverter)d).OnUnitChanged(e);
        }

        protected virtual void OnUnitChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        #endregion


        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
// you can use the dependency property here
...
}
}

and in your xaml:

<UserControl.Resources>
    <converters:WattHoursConverter x:Key="WattHoursConverter" Unit="{Binding UnitPropFromDataContext}"/>
 </UserControl.Resources>
....
  <TextBlock Grid.Column="1" TextWrapping="Wrap" Text="{Binding TotalCO2, Converter={StaticResource KgToTonnesConverter}}" FontSize="13.333" />
PhearOfRayne
  • 4,762
  • 3
  • 28
  • 44
Adam Bilinski
  • 1,158
  • 1
  • 18
  • 28
  • This looks like it should work, but I get the old "Cannot find governing FrameworkElement or FrameworkContentElement for target element", "DataItem=null" business. Is UnitPropFromDataContext a property of your viewmodel? Not that matters if the binding has no DataItem anyhow. – 15ee8f99-57ff-4f92-890c-b56153 Feb 02 '15 at 20:27
  • This is horrific but it's the only thing that works for me: void View_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { (FindResource("ConverterKey") as ConverterType).PropertyName = (DataContext as ViewModelType).ViewModelProperty; } – 15ee8f99-57ff-4f92-890c-b56153 Feb 02 '15 at 20:39
1

It is possible by creating an own Binding which supports binding to the ConverterParameter. Here is how to use it:

<RadioButton Content="{Binding Path=Mode}" 
    IsChecked="{BindingWithBindableConverterParameter Converter={StaticResource ParameterModeToBoolConverter},
    ConverterParameter={Binding Path=DataContext.SelectedMode,ElementName=root}}" />

And the code with the implementation for this binding:

[ContentProperty(nameof(Binding))]
public class BindingWithBindableConverterParameter : MarkupExtension
{
    public Binding Binding { get; set; }
    public BindingMode Mode { get; set; }
    public IValueConverter Converter { get; set; }
    public Binding ConverterParameter { get; set; }

    public BindingWithBindableConverterParameter()
    { }

    public BindingWithBindableConverterParameter(string path)
    {
        Binding = new Binding(path);
    }

    public BindingWithBindableConverterParameter(Binding binding)
    {
        Binding = binding;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var multiBinding = new MultiBinding();
        Binding.Mode = Mode;
        multiBinding.Bindings.Add(Binding);
        if (ConverterParameter != null)
        {
            ConverterParameter.Mode = BindingMode.OneWay;
            multiBinding.Bindings.Add(ConverterParameter);
        }
        var adapter = new MultiValueConverterAdapter
        {
            Converter = Converter
        };
        multiBinding.Converter = adapter;
        return multiBinding.ProvideValue(serviceProvider);
    }

    [ContentProperty(nameof(Converter))]
    private class MultiValueConverterAdapter : IMultiValueConverter
    {
        public IValueConverter Converter { get; set; }

        private object lastParameter;

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (Converter == null) return values[0]; // Required for VS design-time
            if (values.Length > 1) lastParameter = values[1];
            return Converter.Convert(values[0], targetType, lastParameter, culture);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            if (Converter == null) return new object[] { value }; // Required for VS design-time

            return new object[] { Converter.ConvertBack(value, targetTypes[0], lastParameter, culture) };
        }
    }
}
Apfelkuacha
  • 644
  • 8
  • 20
0

I have found a related SO post that I believe answers this question:

WPF ValidationRule with dependency property

In my specific example I end up with xaml that looks like this having implemented the above example:

<conv:BindingProxy x:Key="iconCacheHolder" Value="{Binding ElementName=This,Path=IconCache}" />
<conv:UriImageConverter  x:Key="ImageConverter">
    <conv:UriImageConverter.Proxy>
        <conv:IconCacheProxy Value="{Binding Value, Source={StaticResource iconCacheHolder}}" />
    </conv:UriImageConverter.Proxy>
</conv:UriImageConverter>
Mark
  • 1
  • 2