How can I set a dependency property on a static resource?
Asked Answered
T

2

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 :)

Twopenny answered 5/5, 2011 at 19:59 Comment(0)
P
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.

Piranesi answered 5/5, 2011 at 20:35 Comment(1)
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.Twopenny
W
1

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}").

Wacke answered 5/5, 2011 at 21:41 Comment(6)
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}".Twopenny
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.Wacke
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.Twopenny
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)Wacke
"(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.Twopenny
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.Wacke

© 2022 - 2024 — McMap. All rights reserved.