Binding from resources inside a DataTemplate

2019-07-18 22:09发布

问题:

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:

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>