Search code examples
wpfdata-bindingdatatrigger

How can I replace an image in a WPF grid with another control depending on the source data?


I have a grid laid out like so;

+---------+---------+
|  Image  | Details |
|    is   |  pane   |
|  here   | for data|
|         |  entry  |
+---------+---------+
| ListView here to  |
| select data item  |
| for top two panes |
+---------+---------+

This all works well, but I would now like to change the image to another set of controls saying 'Sorry, no image available' when the selected item in the listview does not have an image

I've tried wrapping the image in a DockPanel and setting a DataTemplate there (so I can use DataTriggers) but IntelliSense says no!

The ListView uses DataTriggers to do a similar thing, but as I say I can't get my head round how to do it for a single image that does not seem to have access to a DataTemplate.

Simplified XAML is below;

<Grid DataContext="{Binding Source={StaticResource MyData}}">
   <!-- row 0 col 0 -->
   <Image x:Name="imgPhoto" Source="{Binding ElementName=MyListViewOfData, Path=SelectedItem.PathToImageOnDisk}" />

   <!-- row 0 col 1 -->
   <StackPanel DataContext="{Binding ElementName=MyListViewOfData, Path=SelectedItem}">
      <TextBox Name="NameTextBox" Text="{Binding Name}" />
      <TextBlock Name="DateCreatedTextBlock" Text="{Binding DateCreated}" />
   </StackPanel>

   <!-- row 1 cols 0,1 -->
   <ListView ItemsSource="{Binding}" ItemTemplate="{StaticResource MyListViewTemplate}" 
IsSynchronizedWithCurrentItem="True" Name="MyListViewOfData" />

</Grid>

Thanks in advance WPF gurus.

Ryan

Update: Both answers below (Abe and Jobi) were spot on, thanks.


Solution

  • In order to use a DataTemplate, you have to have a control that uses the template to render an object. If you use a ContentPresenter, you can set its ContentTemplate to be a DataTemplate to whatever you like.

    Here is how I would do this:

    <Grid DataContext="...">
        <ContentPresenter Content="{Binding SelectedItem, ElementName=MyListViewOfData}">
            <ContentPresenter.ContentTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition />      
                        </Grid.ColumnDefinitions>
                        <Image x:Name="imgPhoto" Source="{Binding PathToImageOnDisk}" />
                        <TextBlock x:Name="error" Visibility="Collapsed" Text="Sorry, no image available" />
                        <StackPanel Grid.Column="1">
                            <TextBox Name="NameTextBox" Text="{Binding Name}" />
                            <TextBlock Name="DateCreatedTextBlock" Text="{Binding DateCreated}" />
                        </StackPanel>
                    </Grid>
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding PathToImageOnDisk}" Value="{x:Null}">
                        <Setter TargetName="imgPhoto" Property="Visibility" Value="Collapsed" />
                        <Setter TargetName="error" Property="Visibility" Value="Visible" />
                    </DataTrigger>
                </DataTemplate.Triggers>
                </DataTemplate>
            </ContentPresenter.ContentTemplate>
        </ContentPresenter>
        <ListView ItemsSource="{Binding}" ItemTemplate="{StaticResource MyListViewTemplate}" IsSynchronizedWithCurrentItem="True" Name="MyListViewOfData" />
    
    </Grid>