I stumbled over this post in the MSDN's WPF-Forum today where the OP was asking for a way to add a watermark to a ListView (i.e. a background-image). Thought this would make up for a quick blog post, so here goes.
The Basics
Tasks like this one are easy to accomplish in WPF by means of a ControlTemplate. That is, taking an arbitrary style that already exists for the control in question, you simply take the predefined one and add whatever is required to solve the imposed task.
Now, there's two good places to get a control's template. The MSDN offers a sample for just about every control you can think of. Starting at the ControlTemplate section, you'll find them in the left section (press "t" to toggle the TreeView section's visibility in your browser - this works at least for Firefox and IE). Here's a screenshot (click to enlarge):

If you click any link in the left section, you'll find an example of a ControlTemplate on the linked page if you scroll down a bit.
For most of all times though, I prefer use a tool called StyleSnooper to get at a template. IMHO it's one of several tools that every WPF-developer should have (and it's free, too!). Thanks to everybody that was involved making it! Here's a screenshot (click to enlarge):

The default ControlTemplate
Alright, so here's the (relevant portions of the) default ControlTemplate that StyleSnooper gives me on my system (I'm still running WinXP and VS2008; note that it could be different on yours):
<Style TargetType="{x:Type ListBox}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:System;assembly=mscorlib">
(*** Setters skipped ***)
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="1,1,1,1" BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}" Name="Bd" SnapsToDevicePixels="True">
<ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
(*** Triggers skipped ***)
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In the ControlTemplate, we can see that the ItemsPresenter (which is the element that renders the control's items) is wrapped in a ScrollViewer (which will provide the ScrollBars) which in turn is wrapped in a Border (which makes up for the line around the control). This is the place where we can add our own stuff in order to extend what's already there.
Where to display the Watermark?
Depending on where we want the watermark to appear, the task can by anything from blazingly simple to a bit tedious. There's actually two different places that I can think of for displaying the image in the lower right. One would be the "absolute" lower right, that is, the bottom right of the ScrollViewer's content. This means that, if the overall size of all items is larger than what can be hosted in the ListView's content, resulting in the ScrollBar(s) appearing, the image would stick to the position of the last item in the list. This would also mean that the watermark would only be visible if you scrolled to the bottom right. This is actually quite easy (as would be if you wanted the image centered or in the top left).
The second place I can think of is the lower right of the ListView control itself. That is, assuming the watermark should be visible at all times, not the ScrollViewer's bottom right but rather that of the ListView itself.
The fundamental approach
For both scenarios, the simplest approach I can think of is to use the Grid-control in order to sub-divide the ListView's content area into four cells (i.e. two rows and two columns) and then placing the image into the lower right cell, which would give us the alignment we're looking for. The actual content can then be spread over all 4 cells, using the Grid-attached properties ColumnSpan and RowSpan. Since the Grid control supports more than a single piece of content, it will simply overlay any controls that occupy the same area - one over the other - giving us exactly what we're after.
Displaying the watermark in the lower right of the ScrollViewer
This is pretty straight forward - all we need to do is to create a Grid inside the Border of the default ControlTemplate, defining the two rows and two columns, then adding both the image and the original content (i.e. the ScrollViewer and the ItemsPresenter within). Here, the image is placed into the lower right cell (which is the only cell where height and width are set to Auto) while the other three cells take whatever width remains. This makes up for the bottom right alignment.
The ItemsPresenter, on the other hand, will simply be spread over all rows and columns, hence consuming whatever real estate is available.
Here's the XAML, reduced to the ControlTemplate and without the Triggers:
<ControlTemplate TargetType="{x:Type ListBox}">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="1,1,1,1" BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}" Name="Bd" SnapsToDevicePixels="True">
<ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Grid.Row="1" Grid.Column="1"
Name="BackgroundImage"
Source="/Resources/SampleImage.png"
Margin="0,0,1,1"/>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
Grid.RowSpan="2" Grid.ColumnSpan="2"/>
</Grid>
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
(*** Triggers skipped ***)
</ControlTemplate.Triggers>
</ControlTemplate>
As you can see, there now is a Grid inside the ScrollViewer. Since the image is placed into the lower right cell, it'll simply stick to the bottom right of the ScrollViewer's content (as opposed to its extent, i.e. the visible portion).
Unless you want this behavior though, the problem with this approach is that you won't see the image unless you scroll to the bottom right. Here's two screenshots of the sample solution's window in action (if you follow along with the project running, click the "A. ..."-button for this window); the left one shows the window after opening it, the right one after having scrolled down to the bottom right:

I can't really think of a scenario where this layout would be desired. So let's move on to adding some more stuff to assure the image is visible all the time.
Displaying the watermark in the lower right of the ListView
So, what would we have to do in order to display the image in the lower right of the ListView control instead, i.e. visible regardless of the ScrollViewer's current position? Again, this is easily accomplished by moving the Grid control added in the last step out of the ScrollViewer and - up by one level - into the Border. Here's the amended XAML:
<ControlTemplate TargetType="{x:Type ListBox}">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="1,1,1,1" BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}" Name="Bd" SnapsToDevicePixels="True">
<!-- The Grid allows the Image to appear on the bottom right -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!--
The watermark image, placed in the lower right cell of the Grid.
-->
<Image Grid.Row="1" Grid.Column="1"
Name="BackgroundImage"
Source="/Resources/SampleImage.png"
Width="64"
Height="64"
Margin="0,0,1,1"/>
<ScrollViewer Name="sv" Grid.RowSpan="2" Grid.ColumnSpan="2"
Padding="{TemplateBinding Control.Padding}" Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Grid>
</Border>
<ControlTemplate.Triggers>
(*** Triggers skipped ***)
</ControlTemplate.Triggers>
</ControlTemplate>
However, while this is fine as long as no ScrollBars are present (just as with the first sample), this will lead to the ScrollBars appearing above the image (click the "B1. ..."-button if you're running the sample project):

We probably don't want that, do we.
(Multi)Triggers to the rescue
In order to allow the image to always appear at the bottom right of the ScrollViewer's visible area, let's add a couple of Triggers. The approach is again simple - by monitoring the Computed[Horizontal/Vertical]ScrollBarVisibility, we can create a Trigger for each of the three possible states - both scrollbars being visible, the horizontal one being visible with the vertical being hidden and, finally, the horizontal being hidden with the vertical one being visible. Here's the XAML that I added to the ControlTemplate's Triggers collection:
<!--
The MultiTriggers below will change the Margin of the BG-image depending on the visibility of scrollbars ->
-->
<!-- MT #1: only the vertical ScrollBar is visible -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition SourceName="sv" Property="ComputedVerticalScrollBarVisibility" Value="Visible"/>
<Condition SourceName="sv" Property="ComputedHorizontalScrollBarVisibility" Value="Collapsed"/>
</MultiTrigger.Conditions>
<Setter TargetName="BackgroundImage" Property="Margin" Value="0,0,17,1"/>
</MultiTrigger>
<!-- MT #2: only the horizontal ScrollBar is visible -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition SourceName="sv" Property="ComputedVerticalScrollBarVisibility" Value="Collapsed"/>
<Condition SourceName="sv" Property="ComputedHorizontalScrollBarVisibility" Value="Visible"/>
</MultiTrigger.Conditions>
<Setter TargetName="BackgroundImage" Property="Margin" Value="0,0,1,17"/>
</MultiTrigger>
<!-- MT #3: both ScrollBars are visible -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition SourceName="sv" Property="ComputedVerticalScrollBarVisibility" Value="Visible"/>
<Condition SourceName="sv" Property="ComputedHorizontalScrollBarVisibility" Value="Visible"/>
</MultiTrigger.Conditions>
<Setter TargetName="BackgroundImage" Property="Margin" Value="0,0,17,17"/>
</MultiTrigger>
As you can see, all I've done is to change the (right and/or bottom) Margin of the Image control, depending on the state of the ScrollViewer's ScrollBars.
Wrapping it all up
Another thing I simply forgot doing until here is to change the Image's Opacity so that it leaves the impression of translucency. Here's the complete XAML of the last Window in the sample solution:
<Window x:Class="ListViewWithWatermarkImage.B_2_LV_BottomRight"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ListViewWithWatermarkImage"
Height="300" Width="150" MinWidth="150">
<Window.Resources>
<Style TargetType="{x:Type ListView}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:System;assembly=mscorlib">
<Style.Resources>
<ResourceDictionary />
</Style.Resources>
<Setter Property="Panel.Background">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.WindowBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="Border.BorderBrush">
<Setter.Value>
<SolidColorBrush>#FF828790</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="Border.BorderThickness">
<Setter.Value>
<Thickness>1,1,1,1</Thickness>
</Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlTextBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility">
<Setter.Value>
<x:Static Member="ScrollBarVisibility.Auto" />
</Setter.Value>
</Setter>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility">
<Setter.Value>
<x:Static Member="ScrollBarVisibility.Auto" />
</Setter.Value>
</Setter>
<Setter Property="ScrollViewer.CanContentScroll">
<Setter.Value>
<s:Boolean>True</s:Boolean>
</Setter.Value>
</Setter>
<Setter Property="Control.VerticalContentAlignment">
<Setter.Value>
<x:Static Member="VerticalAlignment.Center" />
</Setter.Value>
</Setter>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="1,1,1,1" BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}" Name="Bd"
SnapsToDevicePixels="True">
<!-- The Grid allows the Image to appear on the bottom right -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!--
The watermark image, placed in the lower right cell of the Grid.
-->
<Image Grid.Row="1" Grid.Column="1"
Name="BackgroundImage"
Source="/Resources/SampleImage.png"
Width="64"
Height="64"
Opacity="0.2"
Margin="0,0,1,1"/>
<!--
The border below will simply overlay the complete contents of the control
(including the image) and thus create the impression the image was not
completely opaque.
-->
<!--<Border Grid.RowSpan="2" Grid.ColumnSpan="2"
Background="{TemplateBinding Panel.Background}" Opacity="0.8"/>-->
<!--
The rest is the original ScrollViewer; the only change is the RowSpan
and ColumnSpan which makes the control cover the complete extent of
the Grid control (just like the Border above).
-->
<ScrollViewer Name="sv" Grid.RowSpan="2" Grid.ColumnSpan="2"
Padding="{TemplateBinding Control.Padding}" Focusable="False">
<ItemsPresenter
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Grid>
<!-- Original: -->
<!--
<ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
-->
</Border>
<ControlTemplate.Triggers>
<!--
The MultiTriggers below will change the Margin of the BG-image depending on the
visibility of scrollbars ->
-->
<!-- MT #1: only the vertical ScrollBar is visible -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition SourceName="sv" Property="ComputedVerticalScrollBarVisibility"
Value="Visible"/>
<Condition SourceName="sv" Property="ComputedHorizontalScrollBarVisibility"
Value="Collapsed"/>
</MultiTrigger.Conditions>
<Setter TargetName="BackgroundImage" Property="Margin" Value="0,0,17,1"/>
</MultiTrigger>
<!-- MT #2: only the horizontal ScrollBar is visible -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition SourceName="sv" Property="ComputedVerticalScrollBarVisibility"
Value="Collapsed"/>
<Condition SourceName="sv" Property="ComputedHorizontalScrollBarVisibility"
Value="Visible"/>
</MultiTrigger.Conditions>
<Setter TargetName="BackgroundImage" Property="Margin" Value="0,0,1,17"/>
</MultiTrigger>
<!-- MT #3: both ScrollBars are visible -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition SourceName="sv" Property="ComputedVerticalScrollBarVisibility"
Value="Visible"/>
<Condition SourceName="sv" Property="ComputedHorizontalScrollBarVisibility"
Value="Visible"/>
</MultiTrigger.Conditions>
<Setter TargetName="BackgroundImage" Property="Margin" Value="0,0,17,17"/>
</MultiTrigger>
<!--
<- The MultiTriggers below will change the Margin of the BG-image depending on
the visibility of scrollbars
-->
<Trigger Property="UIElement.IsEnabled">
<Setter Property="Panel.Background" TargetName="Bd">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>
False</s:Boolean>
</Trigger.Value>
</Trigger>
<Trigger Property="ItemsControl.IsGrouping">
<Setter Property="ScrollViewer.CanContentScroll">
<Setter.Value>
<s:Boolean>
False</s:Boolean>
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>
True</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<ListView Margin="10" MinHeight="100" MinWidth="100">
<ListViewItem>ListViewItem (with somewhat lengthy text) #1</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #2</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #3</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #4</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #5</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #6</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #7</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #8</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #9</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #10</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #11</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #12</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #13</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #14</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #15</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #16</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #17</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #18</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #19</ListViewItem>
<ListViewItem>ListViewItem (with somewhat lengthy text) #20</ListViewItem>
</ListView>
</Window>
And here's two screenshots of the sample window (click the "B2. ..."-button to view this Window), with and without the ScrollBars being visible:

But wait!
That pretty much concludes the article. However, I guess a few other things are worth to be mentioned:
- The margin of "17" (in the MultiTriggers) is my attempt to keep it simple. Considering the fact that we want to move the image to the left and/or up depending on the ScrollBar(s) Visibility, we need to do so by means of the height/width of the respective ScrollBar. Now if we wanted to determine the width of the ScrollBar at runtime, we would really require a converter that would take the width on a given system (usually it's just 16) and add one unit to it (i.e. the Image's general Margin).
- There's a slight tripping hazard to this - if your watermark image is larger than the size of the ListView, the ListView will simply expand until the image fits it in. As a result, if you shrink the containing Window far enough, you'll see the ScrollViewer's ScrollBars disappear. It would certainly be feasible to provide a work-around for that as well, but I presume this should be a rarely encountered situation on one hand and it's getting late (and the Snooker World Championship's final is coming up) on the other, so I won't venture into that.
The sample solution
I’ve created a sample solution that contains everything discussed here. Since there is no code-behind (except for the three Button-click-handlers) involved, the solution only contains a C# project - there is no VB counterpart. However, if you want to use this in a VB-project, simply paste the XAML into your VB-window and remove the ListViewWithWatermarkImage. that is preceding each window's x:Class attribute (and indicating the namespace required for C#).
Download: ListViewWithWatermarkImage.zip (36.87 kb)
Location: SinglePost