1

I have a horrible feeling what I'm trying to do cannot be done, but here goes. Maybe there's a better way.

I have a ResourceDictionary in a separate file, being pulled into a UserControl (View):

<UserControl.Resources>        
    <ResourceDictionary Source="..\Resources.xaml"/>
</UserControl.Resources>

In the RD, I define some button styles, one of which includes a Condition, setting the Foreground to Red if the "IsCurrentFilter" converter returns True:

<Style x:Key="FilterButton" TargetType="Button" BasedOn="{StaticResource ButtonBase}">
    <Style.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding Converter={StaticResource IsCurrentFilter}}" Value="True"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Foreground" Value="Red" />
        </MultiDataTrigger>
    </Style.Triggers>
</Style>

The converter is defined in the same RD, further up:

<util:IsCurrentFilterConverter x:Key="IsCurrentFilter" ViewModel="{Binding}"/>

The problem is that the converter has no access to the view model (which it requires to do its comparison), and the ViewModel property simply refuses to bind to anything. The error is...

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:(no path); DataItem=null; target element is 'IsCurrentFilterConverter' (HashCode=50804710); target property is 'ViewModel' (type 'Object')

...which kinda makes sense, as I understand it's not in the visual tree.

So, how can I bind to the view model inside this ResourceDictionary?

Anatoliy Nikolaev
  • 22,370
  • 15
  • 69
  • 68
Antony Woods
  • 4,415
  • 3
  • 26
  • 47

2 Answers2

2

You're doing it wrong. A converter should not be bound to the viewmodel in this way. It should depend solely on its input value(s). Set up your button in such a way that the viewmodel is the button's data context or is available in a predictable place up the logical tree. Then your binding's converter can 'convert' the viewmodel into a boolean value. Even better, add a viewmodel property providing the desired boolean and bind to it instead.

Anton Tykhyy
  • 19,370
  • 5
  • 54
  • 56
  • I agree, it should solely depend on its input values. I started out by simply comparing the current filter from the view model directly, but apparently the ConverterParameter isn't a DependencyProperty. Anyway, unfortunately, I can't change/control the DataContext of the Button because I require it to be a Filter for styling. – Antony Woods Feb 15 '13 at 09:32
  • To follow up, this suggestion actually just inverts the problem. Now I have access to the ViewModel but no idea which Filter is being referenced in the converter. – Antony Woods Feb 15 '13 at 09:47
  • It's simple enough. You have two options: 1) provide the filter with a reference to the viewmodel — it's often useful for a lot of stuff; 2) make a multi-value converter and pass in both the filter and the viewmodel (find it using e.g. `{RelativeSource FindAncestor}`). – Anton Tykhyy Feb 15 '13 at 12:07
  • I'll mark this as the answer because it's better advice than the real answer is. – Antony Woods Mar 08 '13 at 13:44
2

Just in case anyone stumbles upon this, I chose a different technique to solve the problem. However, binding inside a resource is something that's been fixed here:

http://www.codeproject.com/Articles/27432/Artificial-Inheritance-Contexts-in-WPF

Antony Woods
  • 4,415
  • 3
  • 26
  • 47