2

Is there some way to get the DataContext of a DataTemplate to use in bindings within its resources?

<DataTemplate x:Key="History"> <ItemsControl ItemsSource="{Binding History}"> <ItemsControl.Resources> <app:BitmapProvider x:Key="Converter" ShowDetails="True" Type="{Binding Model.Type}" /> </ItemsControl.Resources> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal" IsItemsHost="True"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Image Source="{Binding Data, Converter={StaticResource Converter}}" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </DataTemplate> 

The above template is used as the CellTemplate of a ListBox. The object at that level has two properties, History (containing a list of "historic info" objects) and Model (containing a bunch of other stuff, including Type). I'm using an ItemsControl to display the historic items next to each other; I want to display an image for each one, and the image is obtained from the BitmapProvider, which is an IValueConverter.

The converter needs two bits of info to obtain a result: one is the Data of the individual historic items, and the other is the Type of the whole collection. An added complication is that constructing this particular converter (or changing the Type given to it) is expensive, so I don't want to put it at the level of the individual history item, or to use a MultiBinding, and I can't put it outside of the template because then it won't have access to the Type.

Unfortunately, the above gives me the following error:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Model.Type; DataItem=null; target element is 'BitmapProvider' (HashCode=57142809); target property is 'Type' (type 'TypeDetails')

Which I understand to mean that the resource can't figure out how to get the DataContext of the element it's contained within.

(I have searched, and most of the answers I could find suggested moving it outside the template or using a MultiBinding instead -- neither of which would really work in this case, as far as I can tell, as I've explained above. But I'd be delighted to be proven wrong, or given another alternative.)

1 Answer 1

3

I think you can accomplish that with DataContextSpy.

try something like:

<ItemsControl.Resources> <spy:DataContextSpy x:Key="Spy"/> <app:BitmapProvider x:Key="Converter" ShowDetails="True" Type="{Binding DataContext.Model.Type,Source={StaticResource Spy}}" /> </ItemsControl.Resources> 
Sign up to request clarification or add additional context in comments.

3 Comments

That's new to me too. But it works. Thanks! (I am still considering a different solution: extracting the expensive part into a separate class hosted by the collection's ViewModel, and make the converter use that and the item's Data to get its result. But I don't like that as much because it feels too much like polluting the ViewModel with too much View-specific data -- I like being able to share a ViewModel between multiple Views.)
don't worry about this being some kind of hack! If you look at that article's date (July 2008) you see it's been around for a while. The other very useful class is ElementSpy. Keep that on your list of useful WPF helpers too!
Yeah, ElementSpy looks good too. I used to use Dr.WPF's ObjectReferenceExtension for that purpose (which unfortunately uses static data, limiting its usefulness), until I discovered the PlacementTarget trick, which so far has been sufficient. But it's good to have something to fall back to if I need something that PlacementTarget won't work for.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.