3

I'm trying to get around the fact that I can't specify a dynamic value for ConverterParameter. See my other question for why I need to bind a dynamic value to ConverterParameter - I don't like the solutions currently posted because they all require what I feel should be unnecessary changes to my View Model.

To attempt to solve this, I have created a custom converter, and exposed a dependency property on that converter:

public class InstanceToBooleanConverter : DependencyObject, IValueConverter
{
    public object Value
    {
        get { return (object)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(object), typeof(InstanceToBooleanConverter), null);

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value != null && value.Equals(Value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value.Equals(true) ? Value : Binding.DoNothing;
    }
}

Is there a way to set this value using a binding (or style setter, or other crazy method) in my XAML?

<ItemsControl ItemsSource="{Binding Properties}">
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="{x:Type local:SomeClass}">
            <DataTemplate.Resources>
                <!-- I'd like to set Value to the item from ItemsSource -->
                <local:InstanceToBooleanConverter x:Key="converter" Value="{Binding Path=???}" />
            </DataTemplate.Resources>
<!- ... ->

The examples I've seen so far only bind to static resources.

Edit:

I got some feedback that there is only one converter instance with the XAML I posted.

I can work around this by placing the resource in my control:

<ItemsControl ItemsSource="{Binding Properties}">
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="{x:Type local:SomeClass}">
            <RadioButton Content="{Binding Name}" GroupName="Properties">
                <RadioButton.Resources>
                    <!-- I'd like to set Value to the item from ItemsSource -->
                    <local:InstanceToBooleanConverter x:Key="converter"
                                                      Value="{Binding Path=???}" />
                </RadioButton.Resources>
                <RadioButton.IsChecked>
                    <Binding Path="DataContext.SelectedItem"
                             RelativeSource="{RelativeSource AncestorType={x:Type Window}}"
                             Converter="{StaticResource converter}" />
                </RadioButton.IsChecked>
            </RadioButton>
<!- ... ->

So this problem isn't blocked by having to share an instance of the converter :)

Community
  • 1
  • 1
Merlyn Morgan-Graham
  • 58,163
  • 16
  • 128
  • 183

2 Answers2

1

Unfortunately this isn't going to work - I've been down this road before and it turns out all the Items in the ItemsControl share the same Converter. I think this is due to the way the XAML parser works.

default.kramer
  • 5,943
  • 2
  • 32
  • 50
  • Yeah I could see that being a problem. However I noticed if I set it to a resource on the control, then I get an instance per control. I can change my question to do that if it makes more sense. – Merlyn Morgan-Graham May 05 '11 at 20:40
0

Firstly you can specify the converter at a higher level resource dictionary and set x:Shared to false, secondly if you want to "set the Value to the item from ItemsSource" as you annotated you can just specify an empty binding (Value="{Binding}").

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • Thanks for the `x:Shared` info. As for the binding, it seems that the setter for my dependency property never gets called when I do `Value="{Binding}"`. – Merlyn Morgan-Graham May 05 '11 at 21:57
  • Setters of dependency properties are not used by internal mechanisms, they are only for code-behind access. That is why one should never put any code in them except the SetValue/GetValue calls. – H.B. May 05 '11 at 22:08
  • You are right about the setter not getting called. If I change from `Value="{Binding}"` to `Value="{StaticResource someOtherResource}`, the getter returns that static resource instance, but the setter is never called. But when I go back to `Value="{Binding}"`, the getter returns `null`. – Merlyn Morgan-Graham May 05 '11 at 23:56
  • Never mind that, a binding is not a value after all. (At some points in the binding may not return a value so `GetValue` returns `null`) – H.B. May 06 '11 at 00:00
  • "(At some points in the binding may not return a value so GetValue returns null)". Do you mean at some points during application startup/UI creation, or at some points while running the app? In testing this out, I was using a DataContext (set in the constructor) that ensured nothing was null. I'm starting to think this binding is happening at compile time, then serialized. – Merlyn Morgan-Graham May 06 '11 at 02:49
  • Sorry that i did not answer, maybe i somehow overlooked your comment. Binding does happen at runtime, but my analysis was probably just wrong, i would say that this binding will not work because `ValueConverters` do not have a `DataContext` or even visual tree connection. Your sources are limited to the `Source` property, i would expect that `DataContext` (no explicit source), `ElementName` and `RelativeSource` will not work here. – H.B. Jan 02 '12 at 15:07