The ListView control can render items outside the view-port using a 'preview' state. This feature confers highest performance imaginable to the ListView control, especially during data virtualization.
For instance, you can load photos from image hosting service like Flickr. The PreviewItemTemplate property of C1ListView class helps to displays the preview when the photos are not fully loaded.
Like any standard ItemTemplate, the Preview template defines the appearance of items when they are in a preview state, such as zoomed out or during fast scroll. The controls will then switch to the full item template when the items have stopped scrolling or zooming.
Please observe the code snippet below to see how the PreviewItemTemplate property has been used in a desktop app:
<c1:C1ListView x:Name="listView" ItemWidth="240" ItemHeight="192" ViewportGap="0" ViewportPreviewGap="0" > <c1:C1ListView.PreviewItemTemplate> <DataTemplate> <Grid Background="Gray"> <Image Source="{Binding Thumbnail}" Stretch="UniformToFill" /> </Grid> </DataTemplate> </c1:C1ListView.PreviewItemTemplate> <c1:C1ListView.ItemTemplate> <DataTemplate> <Grid> <Image Source="{Binding Content}" Stretch="UniformToFill" /> <TextBlock Text="{Binding Title}" Margin="4 0 0 4" VerticalAlignment="Bottom" /> </Grid> </DataTemplate> </c1:C1ListView.ItemTemplate> <c1:C1ListView.ItemContainerStyle> <!--This style allows showing the preview while the full image is being loaded--> <Style TargetType="c1:ListViewItemView"> <Setter Property="BorderThickness" Value="1" /> <Setter Property="Margin" Value="0" /> <Setter Property="Padding" Value="2" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="c1:ListViewItemView"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal" /> <VisualState x:Name="PointerOver"> <Storyboard> <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PointerOverBorder" /> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="DesignBrush" Storyboard.TargetName="SelectedBackground"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <SolidColorBrush Color="#FF5F37BE" /> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <DoubleAnimation Duration="0" To=".55" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Content" /> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="PreviewStates"> <VisualState x:Name="Full"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="(UIElement.Visibility)"> <DiscreteObjectKeyFrame KeyTime="00:00:00"> <DiscreteObjectKeyFrame.Value> <Visibility>Visible</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Preview"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="(UIElement.Visibility)"> <DiscreteObjectKeyFrame KeyTime="00:00:00"> <DiscreteObjectKeyFrame.Value> <Visibility>Collapsed</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="SelectionStates"> <VisualState x:Name="Unselected"> <Storyboard> </Storyboard> </VisualState> <VisualState x:Name="Selected"> <Storyboard> <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="SelectionBackground" /> <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="SelectedBorder" /> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <CheckBox x:Name="CheckBox" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}" IsChecked="{TemplateBinding IsSelected}" Opacity="0" Foreground="{TemplateBinding Foreground}"/> <Path x:Name="HintingCheckMark" Data="F1 M133.1,17.9 L137.2,13.2 L144.6,19.6 L156.4,5.8 L161.2,9.9 L145.6,28.4 z" Fill="{TemplateBinding SelectedBackground}" HorizontalAlignment="Right" Margin="{TemplateBinding BorderThickness}" Opacity="0" Stretch="Uniform" VerticalAlignment="Top" Width="6" /> <Grid x:Name="Hinting"> <Border x:Name="ContentBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"> <Grid> <Rectangle x:Name="SelectionBackground" Fill="{TemplateBinding SelectedBackground}" Opacity="0" /> <Rectangle x:Name="PointerOverBorder" Fill="{TemplateBinding MouseOverBrush}" IsHitTestVisible="False" Opacity="0" /> <Grid Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"> <ContentControl x:Name="PreviewElement" Content="{TemplateBinding PreviewContent}" ContentTemplate="{TemplateBinding PreviewContentTemplate}" Visibility="Visible" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"/> <ContentPresenter x:Name="Content" Visibility="Collapsed" /> </Grid> </Grid> </Border> <c1:C1BrushBuilder x:Name="SelectedBackground" Input="{TemplateBinding SelectedBackground}" DesignColor="#FF4617B4" DesignBrush="#FF4617B4" /> <Border x:Name="SelectedBorder" IsHitTestVisible="False" Opacity="0" BorderBrush="{Binding Output,ElementName=SelectedBackground}" BorderThickness="{TemplateBinding BorderThickness}"> <Grid x:Name="SelectedCheckMark" Height="15" Width="15" HorizontalAlignment="Right" IsHitTestVisible="False" VerticalAlignment="Top"> <Path x:Name="SelectedEarmark" Data="M0,0 L40,0 L40,40 z" Fill="{Binding Output,ElementName=SelectedBackground}" Stretch="Fill" /> <Path Data="F1 M133.1,17.9 L137.2,13.2 L144.6,19.6 L156.4,5.8 L161.2,9.9 L145.6,28.4 z" Fill="{TemplateBinding Foreground}" HorizontalAlignment="Right" Stretch="Uniform" VerticalAlignment="Top" Width="6" Margin="2" /> </Grid> </Border> </Grid> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </c1:C1ListView.ItemContainerStyle> </c1:C1ListView>
public MainWindow() { InitializeComponent(); LoadPhotos(); } private void LoadPhotos() { var flickrUrl = "http://api.flickr.com/services/feeds/photos_public.gne?tags=animals"; var AtomNS = "http://www.w3.org/2005/Atom"; loading.Visibility = Visibility.Visible; listView.Visibility = Visibility.Collapsed; retry.Visibility = Visibility.Collapsed; var photos = new List<Photo>(); var client = new WebClient(); client.OpenReadCompleted += (s, e) => { try { // parse flickr data var doc = XDocument.Load(new XmlTextReader(e.Result)); foreach (var entry in doc.Descendants(XName.Get("entry", AtomNS))) { var title = entry.Element(XName.Get("title", AtomNS)).Value; var enclosure = entry.Elements(XName.Get("link", AtomNS)).Where(elem => elem.Attribute("rel").Value == "enclosure").FirstOrDefault(); var contentUri = enclosure.Attribute("href").Value; photos.Add(new Photo() { Title = title, Content = contentUri, Thumbnail = contentUri.Replace("_b", "_m") }); } listView.ItemsSource = photos; loading.Visibility = Visibility.Collapsed; listView.Visibility = Visibility.Visible; retry.Visibility = Visibility.Collapsed; } catch { MessageBox.Show("There was an error when attempting to download data from Flickr."); listView.Visibility = Visibility.Collapsed; loading.Visibility = Visibility.Collapsed; retry.Visibility = Visibility.Visible; } }; client.OpenReadAsync(new Uri(flickrUrl)); } private void Retry_Click(object sender, RoutedEventArgs e) { LoadPhotos(); } } public class Photo { public string Title { get; set; } public string Thumbnail { get; set; } public string Content { get; set; } }