Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Silverlight Pictures Album Control

0.00/5 (No votes)
7 May 2010 1  
Silverlight pictures album control with zooming and slideshow.

Introduction

In one of my Silverlight projects, the requirement is to show a slide show of the pictures online and the zooming functionality needs to be implemented. I created a reusable control in Silverlight using the 'Silverlight Templated Control' available in Silverlight Tools. Here, I want to share my code for the album which uses an XML file to show images from a server from multiple folders which are mapped to the album.

Using the code

The goal is to create a album control that is reusable in a Silverlight project, as below:

<grid x:name="LayoutRoot" />
    <xamlalbum x:name="XAlbum" albumsrc="Album.xml" 
       borderthickness="1" borderbrush="Black" 
       disablealbumselection="True" slideduration="3" 
       height="500" width="600" imgsource="Babies" />
</grid />

To get an output like this:

Album.JPG

Developing the control

Create a new 'Silverlihgt Class Library' project to create the control and to build a .dll file to distribute the control.

NewProject.JPG

Add a new control of type 'Silverlight Templated Control' to create our control:

SLTemplate.JPG

This will create a class file for the code-behind of the control, and the Generic.xml under Theme folder, which contains the template of our control.

ProjectTree.JPG

The following is the template code which has the next and previous buttons and other buttons for the slideshow and folder selection. There is a slider control for zooming of the control. A MouseWheel event is also added on the image to zoom.

<ResourceDictionary
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       xmlns:local="clr-namespace:SLNuke"> 

     <Style TargetType="local:XAMLAlbum">
        <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:XAMLAlbum"> 
                <Border Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}">
                    <Canvas Name="root" Width="{TemplateBinding Width}"
                        local:Clip.ToBounds="True"
                        Height="{TemplateBinding Height}" Margin="0,0,0,0" >
                        <Canvas.Resources>
                            <Storyboard x:Name="SlideShow">
                            <ObjectAnimationUsingKeyFrames 
                                BeginTime="00:00:00" 
                                x:Name="objectSS"
                                Storyboard.TargetProperty="Text"
                                Storyboard.TargetName="txtCurrentImg">
                                </ObjectAnimationUsingKeyFrames>
                            </Storyboard>
                            <Style TargetType="Button" 
                                   x:Name="AlbumButtonStyle">
                                <Setter Property="Template">
                                    <Setter.Value>
                                    <ControlTemplate>
                                        <Border Background="White" 
                                           BorderBrush="black" 
                                           BorderThickness="2">
                                        <Canvas Background="Transparent" 
                                               Width="20" Height="20"
                                               HorizontalAlignment="Center" 
                                               VerticalAlignment="Center">
                                            <TextBlock Canvas.Left="6" 
                                                Canvas.Top="3" 
                                                HorizontalAlignment="Center" 
                                                VerticalAlignment="Center"
                                                Foreground="black" 
                                                FontFamily="Arial" 
                                                FontWeight="Bold" 
                                                FontSize="14"
                                                Text="{TemplateBinding Content}">
                                            </TextBlock>
                                        </Canvas>
                                        </Border>
                                    </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                            <Style TargetType="Button" 
                                  x:Name="SlideShowButtonStyle">
                                <Setter Property="Template">
                                    <Setter.Value>
                                        <ControlTemplate>
                                            <Border Background="White" 
                                                   BorderBrush="black" 
                                                   BorderThickness="2">
                                                <Canvas Background="Transparent" 
                                                      Width="20" Height="20"
                                                      HorizontalAlignment="Center" 
                                                      VerticalAlignment="Center">
                                                    <Rectangle Canvas.Top="3" 
                                                       Canvas.Left="3" 
                                                       Width="14" Height="10"
                                                       Stroke="Black" 
                                                       StrokeThickness="1">
                                                    </Rectangle>
                                                    <Line Stroke="Black" 
                                                        StrokeThickness="1" 
                                                        X1="4" Y1="17" 
                                                        X2="9" 
                                                        Y2="13"></Line>
                                                    <Line Stroke="Black" 
                                                        StrokeThickness="1" 
                                                        X1="16" Y1="17" 
                                                        X2="11" Y2="13">
                                                    </Line>
                                                </Canvas>
                                            </Border>
                                        </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                            <Style TargetType="Button" 
                                      x:Name="SlideShowDisabledButtonStyle">
                                <Setter Property="Template">
                                    <Setter.Value>
                                        <ControlTemplate>
                                            <Border Background="White" 
                                                    BorderBrush="black" 
                                                    BorderThickness="2">
                                                <Canvas Background="Transparent" 
                                                       Width="20" Height="20"
                                                       HorizontalAlignment="Center" 
                                                       VerticalAlignment="Center">
                                                    <Rectangle Canvas.Top="3" 
                                                        Canvas.Left="3" 
                                                        Width="14" Height="10"
                                                        Stroke="Black" 
                                                        StrokeThickness="1"></Rectangle>
                                                    <Line Stroke="Black" StrokeThickness="1" 
                                                        X1="4" Y1="17" 
                                                        X2="9" Y2="13"></Line>
                                                    <Line Stroke="Black" StrokeThickness="1" 
                                                        X1="16" Y1="17" 
                                                        X2="11" Y2="13"></Line>
                                                    <Line Stroke="Red" StrokeThickness="1" 
                                                        X1="6" Y1="4" 
                                                        X2="13" Y2="11"></Line>
                                                    <Ellipse Canvas.Top="4" 
                                                        Canvas.Left="6" Width="7" 
                                                        Height="7" Stroke="Red"></Ellipse>
                                                </Canvas>
                                            </Border>
                                        </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style> 
                        </Canvas.Resources>
                        <Image Canvas.Left="0" 
                                Canvas.Top="0" Stretch="Uniform"
                                Source="{TemplateBinding ImgSource}" 
                                Name="mainImg">
                            <Image.RenderTransform>
                                <ScaleTransform x:Name="ImgScaleTransform" 
                                   ScaleX="1" ScaleY="1"></ScaleTransform>
                            </Image.RenderTransform>
                        </Image> 
                        <TextBox Name="txtCurrentImg" 
                           Text="0" Opacity="0"></TextBox>
                        <Button Content=">" 
                            Style="{StaticResource AlbumButtonStyle}"
                            Name="btnNext" Opacity="0.1" 
                            Height="20" Width="20" > 
                        </Button>
                        <Button Content="&lt;" 
                            Style="{StaticResource AlbumButtonStyle}" 
                            Name="btnPrev" Opacity="0.1" 
                            Height="20" Width="20">
                        </Button>
                        <Button Style="{StaticResource SlideShowDisabledButtonStyle}" 
                            Name="btnSlideShow" Opacity="0.1" 
                            Height="20" Width="20">
                        </Button>
                        <Slider x:Name="sldrZoom" 
                            Orientation="Vertical" Opacity="0.2" 
                            Height="100" Width="20"
                            Maximum="10" Minimum="1" 
                            Value="1"></Slider>
                        
                        <Popup Name="ablumList" IsOpen="False">
                            <ListBox Name="lstAlbums" 
                               Margin="0,0,0,0" Padding="0,0,0,0">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                <TextBlock MinWidth="100" 
                                    Text="{Binding}" Height="15"
                                    Foreground="Black" 
                                    FontSize="10"></TextBlock>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                            </ListBox>
                        </Popup>
                        <Image Name="btnAlbums" Opacity="0.2" 
                           Height="30" Width="30"></Image>
                    </Canvas>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    </Style>
</ResourceDictionary>

The album source file (.xml) contains the following format, which contains the albums (folders) to be bound to the control and the picture file names which will be copied to the ClientBin of the project which uses the current control.

<?xml version="1.0" encoding="utf-8" ?>
<Albums>
  <Album Name="Babies">
    <Pic>baby1.jpg</Pic>
    <Pic>baby2.jpg</Pic>
    .....
  </Album>
  ......
</Albums>

In the code-behind XAMLAlbum.cs, load the above XML file by an asynchronous call to the server, which is referenced by the AlbumSrc property to get the list of albums and picture names. Here, I am using the GetTemplateChild() method to get the controls from the template at runtime:

string[] arrPics;
        
public static readonly DependencyProperty AlbumSrcProperty =
       DependencyProperty.Register("AlbumSrc", 
       typeof(String), typeof(XAMLAlbum), null);

    public string AlbumSrc
    {
        get { return (string)GetValue(AlbumSrcProperty); }
        set { SetValue(AlbumSrcProperty, value); }
    }
    
    /// <summary>   
    /// Override the apply template handler.
    /// </summary>   
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        
        ....
        
        SetFirstPicToImage();
    }
        
    public int CurrentImg
    {
        get { return (int)GetValue(CurrentImgProperty); }
        set
        {
            SetValue(CurrentImgProperty, value);
            ShowPicture();
        }
    }

    void SetFirstPicToImage()
    {
        WebClient wc = new WebClient();
        wc.OpenReadCompleted += wc_OpenReadCompleted;
        wc.OpenReadAsync(new Uri(AlbumSrc, UriKind.Relative));
    }
    XDocument doc;
    private void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
    {
        if (e.Error != null)
        {                
            return;
        }
        using (Stream s = e.Result)
        {
            //load the xml file
            doc = XDocument.Load(s);

            //get the current folder name to show that is
            //given by the user in the property ImgSourceProperty
            strFolder = (string)GetValue(ImgSourceProperty);

            var pics = from p in doc.Descendants("Album")
                       where (string)p.Attribute("Name") == strFolder
                       select p;

            var pic = from p in pics.Descendants("Pic")
                      select (string)p;

            arrPics = new string[pic.Count()];
            int ind = 0;

            foreach (string str in pic.ToArray())
            {
                arrPics[ind] = str;
                ind++;
            }

            // this will call method ShowPicture() through
            // the property setter - 0 to show the first picture from album
            CurrentImg = 0;

            //load album names to listbox
            if (GetTemplateChild("lstAlbums") != null)
            {
                ListBox lst = ((ListBox)GetTemplateChild("lstAlbums"));

                var albums = from p in doc.Descendants("Album")
                             select (string)p.Attribute("Name");
                lst.ItemsSource = albums.ToList();
                lst.SelectedIndex = 0;
                
                Canvas root = ((Canvas)GetTemplateChild("root"));

                Popup albumList = ((Popup)GetTemplateChild("ablumList"));
                double left = 3;
                albumList.SetValue(Canvas.LeftProperty, left);
                double top = root.Height - albums.Count() * 15 - 56;
                albumList.SetValue(Canvas.TopProperty, top);
                albumList.MouseLeftButtonUp += 
                  new MouseButtonEventHandler(albumList_MouseLeftButtonUp);
              
                lst.SelectionChanged += 
                  new SelectionChangedEventHandler(lst_SelectionChanged);
            }
        }
    }
        
    void ShowPicture()
    {
        if (arrPics.Length == 0) return;   

        if (CurrentImg < 0)
        {
            CurrentImg = 0;
            return;
        }
        if (CurrentImg > arrPics.Length - 1)
        {
            CurrentImg = arrPics.Length - 1;
            return;
        }

        ImageSourceConverter objImgSrc = new ImageSourceConverter();

        ((Image)GetTemplateChild("mainImg")).SetValue(Image.SourceProperty,
            objImgSrc.ConvertFromString(strFolder + "/" + arrPics[CurrentImg]));
    }

Build the project to get the DLL file.

Using the control in Silverlight applications

Create a new Silverlight project and add a reference to the control DLL. The control can be added to the page like the following:

<UserControl xmlns:my="clr-namespace:SLNuke;assembly=SLNuke"  
      x:Class="SLNukeTest.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      mc:Ignorable="d" d:DesignWidth="640" 
      d:DesignHeight="480">
  <Grid x:Name="LayoutRoot">
    <my:XAMLAlbum ImgSource="Babies" 
       Width="600" Height="500" x:Name="XAlbum"
       SlideDuration="3" DisableAlbumSelection="True"
       BorderBrush="Black" BorderThickness="1" 
       AlbumSrc="Album.xml" ></my:XAMLAlbum>
  </Grid>
</UserControl>

Create a Album.xml file with the above format and copy to the ClientBin of the project. And copy the pictures to the folders with the same names as the album names written in the XML file, and place them under ClientBin (note that I copied the pictures of the albums Babies and Flowers only; Nature will not show as the pictures are not available in the attached project file SLNukeTest).

Flowers.JPG

Points of interest

The control can zoom and play a slideshow. Zooming functionality is useful when picture clarity is not compromised, when the image width and height are decreased on the screen. The album can be set to only one folder, and the property DisableAlbumSelection can be set to true to make the control to show only one folder's pictures and the folder selection button will be hidden.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here