Monday, November 11, 2013

Win 8 - Image Gallery in Window 8 App

In this article i will show you how to display dynamic Group Image Gallery in Window 8 Store App by using GridView Control.

GridViews are often used to hold groups of collections, rather than simple collections.  The GridView template assumes that it will be displaying groups of collections of items, and this can make working with the GridView.

Step 1
Create a Window Store Application and give the solution name as SolImageGallery_Win8App.



Click on Image for better View

Note : Select a 4.5 Framework.

Step 2
Create a New Folder in Solution and give folder name as Images,In that folder add images,it is look like this



Click on Image for better View

Step 3
Create a XML file in the solution and give the file name as ImageData.XML,it is look like this



Click on Image for better View

Step 4
The XML in the following example defines an XML document with a root node called Images. This root node contains one or more nodes called Image that include elements called English Name,Japanese Name and Image Path.
<?xml version="1.0" encoding="utf-8" ?>
<Images>

  <Image>
    <EnglishName>A</EnglishName>
    <JapaneseName>��</JapaneseName>
    <ImagePath>../Images/A.png</ImagePath>
  </Image>

  <Image>
    <EnglishName>Ao</EnglishName>
    <JapaneseName>�</JapaneseName>
    <ImagePath>../Images/Ao.png</ImagePath>
  </Image>

  <Image>
    <EnglishName>Aoba Yamashiro</EnglishName>
    <JapaneseName>山����</JapaneseName>
    <ImagePath>../Images/Aoba.png</ImagePath>
  </Image>

Continue........


</Images>

Note : Refer XML file from Solution.(Download Source Code and view XML file).

Step 5
Create a Image Entity class in the solution,it is look like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SolImageGallery_Win8App
{
    public class ImageEntity
    {
        #region Property

        public String EnglishName
        {
            get;
            set;
        }

        public String JapaneseName
        {
            get;
            set;
        }

        public String ImagePath
        {
            get;
            set;
        }

        #endregion
    }
}

Step 6
Create a KeyGroup class in the solution,it is look like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SolImageGallery_Win8App
{
    public class KeyGroup<TKey,TItems>
    {
        #region Property

        public TKey Key
        {
            get;
            set;
        }

        public IList<TItems> Items
        {
            get;
            set;
        }

        #endregion
    }
}

I would like to display images with names in a GridView,but Grouped by first character of English Name.The trick is a create a KeyGroup class that will allow you to have a Key on which you group the first character of English Name and list of images who match that key.

Step 7
Create an ImageView class in the solution for retrieving Data from XML document,it is look like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

namespace SolImageGallery_Win8App
{
    public static class ImageView
    {
        #region Method

        /// <summary>
        /// Group Image Data
        /// </summary>
        /// <returns>List</returns>
        public static Task<List<KeyGroup<Char, ImageEntity>>> GetGroupImageData()
        {
            try
            {
                return Task.Run<List<KeyGroup<Char, ImageEntity>>>(() => {

                    XDocument XDoc = XDocument.Load("ImageData.xml");

                    // Using Linq Query

                    // First Get All Values from XML file
                    //var QueryImageData = from Q in XDoc.Descendants("Image")
                    //                     select new ImageEntity
                    //                     {
                    //                         EnglishName = Q.Element("EnglishName").Value,
                    //                         JapaneseName = Q.Element("JapaneseName").Value,
                    //                         ImagePath = Q.Element("ImagePath").Value
                    //                     };

                    // Now Group By First Character of English Name and bind this data to KeyGroup Class
                    //var GroupImageQuery =(from Q in QueryImageData
                    //                      group Q by Q.EnglishName.Cast<char>().First() into GB
                    //                      orderby GB.Key
                    //                      select new KeyGroup<Char, ImageEntity>()
                    //                      {
                    //                          Key = GB.Key,
                    //                          Items = GB.ToList()
                    //                      }).ToList();

                    //return GroupImageQuery;

                    // Using Lambda Expression

                    return XDoc.Descendants("Image").Select(LE => new ImageEntity()
                    {
                        EnglishName = LE.Element("EnglishName").Value,
                        JapaneseName = LE.Element("JapaneseName").Value,
                        ImagePath = LE.Element("ImagePath").Value
                    }).ToList().GroupBy(GB => GB.EnglishName.Cast<Char>().First()).OrderBy(OB => OB.Key).Select(KG => new KeyGroup<Char, ImageEntity>()
                    {
                        Key = KG.Key,
                        Items = KG.ToList()
                    }).ToList();

                });
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message); 
            }
        }

        #endregion
    }
}

Step 8
In MainPage.XAML add a GridView Control,it is look like this
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <GridView x:Name="gvImageGallery" SelectionMode="None" VirtualizingStackPanel.VirtualizationMode="Recycling">

        </GridView>
</Grid>

Step 9
Create a CollectionViewSource in Page.Resources ,it is look like this
<Page.Resources>
        <CollectionViewSource x:Name="CVS_ImageGallery" IsSourceGrouped="True" ItemsPath="Items" VirtualizingStackPanel.VirtualizationMode="Recycling"></CollectionViewSource>
    
 </Page.Resources>

The CollectionViewSource manages the collection of lists, and is created in the Resources Section.  Set the IsSourceGrouped property to True and set the ItemsPath to the list of objects (in our case, the Items property in the  KeyGroup class.)

Step 10
Add the following code to define a DataTemplate for display Images with Names and ItemsPanelTemplate for defines the panel that controls the layout of items  in Page.Resources,it is look like this
<Page.Resources>
        <CollectionViewSource x:Name="CVS_ImageGallery" IsSourceGrouped="True" ItemsPath="Items" VirtualizingStackPanel.VirtualizationMode="Recycling"></CollectionViewSource>
        
        <ItemsPanelTemplate x:Key="ImageGalleryItemsPanelTemplate">
            
            <VirtualizingStackPanel Orientation="Horizontal" VirtualizingStackPanel.VirtualizationMode="Recycling"></VirtualizingStackPanel>
        
        </ItemsPanelTemplate>

        <DataTemplate x:Key="ImageGalleryDataTemplate">
         <Grid HorizontalAlignment="Left" Width="250" Height="250">
                
                <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
                    <Image Source="{Binding ImagePath}" Stretch="Fill"  AutomationProperties.Name="{Binding EnglishName}"> </Image>
                </Border>
                
                <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
                    <TextBlock Text="{Binding EnglishName}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="30" Margin="15,0,15,0"/>
                    <TextBlock Text="{Binding JapaneseName}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="30" HorizontalAlignment="Right" Margin="0,0,15,0"/>
                </StackPanel>
            
            </Grid>
        </DataTemplate>
       
    </Page.Resources>

Step 11
Now apply this above templates and CollectionViewSource to the Gridview Control it is like this
<GridView x:Name="gvImageGallery" SelectionMode="None"  ItemsSource="{Binding Source={StaticResource ResourceKey=CVS_ImageGallery}}" ItemsPanel="{StaticResource ImageGalleryItemsPanelTemplate}" ItemTemplate="{StaticResource ImageGalleryDataTemplate}" VirtualizingStackPanel.VirtualizationMode="Recycling">

</GridView>

Step 12
Finally Add a GridView GroupStyle,it is look like this
<GridView x:Name="gvImageGallery" SelectionMode="None"  ItemsSource="{Binding Source={StaticResource ResourceKey=CVS_ImageGallery}}" ItemsPanel="{StaticResource ImageGalleryItemsPanelTemplate}" ItemTemplate="{StaticResource ImageGalleryDataTemplate}" VirtualizingStackPanel.VirtualizationMode="Recycling">
            <GridView.GroupStyle>
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
                                
                                <TextBlock Text='{Binding Key}' Foreground="Orange" FontSize="30" Margin="25,0" FontWeight="Bold" />
                            
                            </Grid>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                    <GroupStyle.Panel>
                        <ItemsPanelTemplate>
                            
                            <VariableSizedWrapGrid Orientation="Vertical"  MaximumRowsOrColumns="2" Margin="25,0" />
                        
                        </ItemsPanelTemplate>
                    </GroupStyle.Panel>
                </GroupStyle>
            </GridView.GroupStyle>
           
        </GridView>

In GridView GroupStyle there are two templates,One for header and another for items.The HeaderTemplate will display the First Character of English Name(in our case Key Property in KeyGroup Class) and ItemsPanelTemplate that creates layout of Items.  

Full XAML Code
<Page
    x:Class="SolImageGallery_Win8App.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SolImageGallery_Win8App"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    
    <Page.Resources>
        <CollectionViewSource x:Name="CVS_ImageGallery" IsSourceGrouped="True" ItemsPath="Items" VirtualizingStackPanel.VirtualizationMode="Recycling"></CollectionViewSource>
        
        <ItemsPanelTemplate x:Key="ImageGalleryItemsPanelTemplate">
            
            <VirtualizingStackPanel Orientation="Horizontal" VirtualizingStackPanel.VirtualizationMode="Recycling"></VirtualizingStackPanel>
        
        </ItemsPanelTemplate>

        <DataTemplate x:Key="ImageGalleryDataTemplate">
         <Grid HorizontalAlignment="Left" Width="250" Height="250">
                
                <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
                    <Image Source="{Binding ImagePath}" Stretch="Fill"  AutomationProperties.Name="{Binding EnglishName}"> </Image>
                </Border>
                
                <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
                    <TextBlock Text="{Binding EnglishName}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="30" Margin="15,0,15,0"/>
                    <TextBlock Text="{Binding JapaneseName}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="30" HorizontalAlignment="Right" Margin="0,0,15,0"/>
                </StackPanel>
            
            </Grid>
        </DataTemplate>
       
    </Page.Resources>
    

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <GridView x:Name="gvImageGallery" SelectionMode="None"  ItemsSource="{Binding Source={StaticResource ResourceKey=CVS_ImageGallery}}" ItemsPanel="{StaticResource ImageGalleryItemsPanelTemplate}" ItemTemplate="{StaticResource ImageGalleryDataTemplate}" VirtualizingStackPanel.VirtualizationMode="Recycling">
            <GridView.GroupStyle>
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
                                
                                <TextBlock Text='{Binding Key}' Foreground="Orange" FontSize="30" Margin="25,0" FontWeight="Bold" />
                            
                            </Grid>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                    <GroupStyle.Panel>
                        <ItemsPanelTemplate>
                            
                            <VariableSizedWrapGrid Orientation="Vertical"  MaximumRowsOrColumns="2" Margin="25,0" />
                        
                        </ItemsPanelTemplate>
                    </GroupStyle.Panel>
                </GroupStyle>
            </GridView.GroupStyle>
           
        </GridView>
    </Grid>
</Page>

Step 13
In Code Behind,On Page Load event Bind the data to CollectionViewSource,it is look like this
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.Storage;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace SolImageGallery_Win8App
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            this.Loaded += async (s, o) => {

                List<KeyGroup<Char, ImageEntity>> ListObj = await ImageView.GetGroupImageData();

                if (ListObj != null)
                {
                    if (ListObj.Count >= 1)
                    {
                        CVS_ImageGallery.Source = await ImageView.GetGroupImageData();
                    }
                }
            };
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.  The Parameter
        /// property is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }
    }
}

Run the Project.

Output



Click on Image for better View

On Simulator



Click on Image for better View

Download
Download Source Code

I had a Created another Simple Image Gallery.

Output



Click on Image for better View

Download
Download Source Code


No comments:

Post a Comment