Windows
8 CP and VS11 are available. Recently I wrote Setting
up Visual Studio11 Beta for Metro Application Creation. In this article we
do some development.
In this
article we will see:
- Creating DataSource
- ListView Binding to DataSource
- Creating ItemTemplate
- Grouping Data Source
- Using SemanticZoomView over
ListView
At the end
of the article we will have output like below:
We are going to display a list of movies in a
ListView. The movies will be grouped with the first letter of their title. Later
in the article we will apply SemanticZoomView on the ListView. In the above
image you can see Semantic Zoom View. To switch between SemanticZoomView and
detail view either you can tap on the screen or press CTRL + Arrow key on the
keyboard.
Create DataSource
The very first thing we need to do is to create a
DataSource. To create a DataSource, right-click on the JS folder and add a new
JavaScript file. Let us call this newly added JavaScript file
moviedata.js
Inside the newly created file, we need to create an
anonymous JavaScript function and define a JavaScript array. This array contains
local data to be bound to the ListView.
MovieArray contains two properties:
- Title to display name of the movie
- Picture to display thumbnail of the
movie.
All the
movie images are inside the images folder in the project. Let us create
an array with sample data. The array is given below:
var
movieArray = [
{ title: "The
Artist",
picture: "images/TheArtist.jpg"
},
{ title: "A
Better Life",
picture: "images/abetterlife.jpg"
},
{ title: "Abduction",
picture: "images/abduction.jpg"
},
{ title: "African Cats",
picture: "images/africancats.jpg"
},
{ title: "Angel Crest",
picture: "images/angelscrest.jpg"
},
{ title: "Arthur",
picture: "images/arthur.jpg"
},
{ title: "Anonymous",
picture: "images/anonymous.jpg"
},
{ title: "A
Dangerous Method",
picture: "images/adangerousmethod.jpg"
},
{ title: "A
Good Old Fashioned Orgy ",
picture: "images/agoodoldfashionedorgy.jpg"
},
{ title: "A
Seperation ",
picture: "images/aseparation.jpg"
},
{ title: "Another Earth ",
picture: "images/anotherearth.jpg"
},
{ title: "A
Heartbeat Away ",
picture: "images/aheartbeataway.jpg"
},
{ title: "Bad
Teacher ",
picture: "images/badteacher.jpg"
},
{ title: "Begineers ",
picture: "images/beginners.jpg"
},
{ title: "Brotherhood ",
picture: "images/brotherhood.jpg"
},
{ title: "Bridesmaids ",
picture: "images/bridesmaids.jpg"
},
{ title: "Born To Be Wild ",
picture: "images/borntobewild.jpg"
},
{ title: "Blackthorn ",
picture: "images/blackthorn.jpg"
},
{ title: "Bellflower ",
picture: "images/bellflower.jpg"
},
{ title: "Butter ",
picture: "images/butter.jpg"
},
{ title: "Bunraku ",
picture: "images/bunraku.jpg"
},
{ title: "Cars 2 ",
picture: "images/cars2.jpg"
},
{ title: "Cost Of A Soul",
picture: "images/costofasoul.jpg"
},
{ title: "Carnage ",
picture: "images/carnage.jpg"
},
{ title: "Crazy Stupid Love ",
picture: "images/crazystupidlove.jpg"
},
{ title: "Cracks ",
picture: "images/cracks.jpg"
},
{ title: "Colombiana ",
picture: "images/colombiana.jpg"
},
{ title: "Cedar Rapids ",
picture: "images/cedarrapids.jpg"
},
{ title: "Captain America ",
picture: "images/captainamerica.jpg"
},
];
Next we need to
convert the JavaScript array into a list to be bound to the ListView.
Now to make this data publicly
available we need to make a namespace and on the HTML page add a reference of
this namespace to use the data from this file. The namespace can be created as
below:
There are
a few points worth discussing about creating the namespace:
- MovieData.itemList is the public member
- MovieData.itemList.datasource will be the
datasource
At this point we have created the DataSource. And
putting all the pieces of code together, the moviedata.js file will be as
below:
Moviedata.js
(function ()
{
"use
strict";
//
http://www.allmoviephoto.com/photo/index_2011.html
var
movieArray = [
{ title: "The
Artist",
picture: "images/TheArtist.jpg"
,
{ title: "A
Better Life",
picture: "images/abetterlife.jpg"
},
{ title: "Abduction",
picture: "images/abduction.jpg"
},
{ title: "African Cats",
picture: "images/africancats.jpg"
},
{ title: "Angel Crest",
picture: "images/angelscrest.jpg"
},
{ title: "Arthur",
picture: "images/arthur.jpg"
},
{ title: "Anonymous",
picture: "images/anonymous.jpg"
},
{ title: "A
Dangerous Method",
picture: "images/adangerousmethod.jpg"
},
{ title: "A
Good Old Fashioned Orgy ",
picture: "images/agoodoldfashionedorgy.jpg"
},
{ title: "A
Seperation ",
picture: "images/aseparation.jpg"
},
{ title: "Another Earth ",
picture: "images/anotherearth.jpg"
},
{ title: "A
Heartbeat Away ",
picture: "images/aheartbeataway.jpg"
},
{ title: "Bad
Teacher ",
picture: "images/badteacher.jpg"
},
{ title: "Begineers ",
picture: "images/beginners.jpg"
},
{ title: "Brotherhood ",
picture: "images/brotherhood.jpg"
},
{ title: "Bridesmaids ",
picture: "images/bridesmaids.jpg"
},
{ title: "Born To Be Wild ",
picture: "images/borntobewild.jpg"
},
{ title: "Blackthorn ",
picture: "images/blackthorn.jpg"
},
{ title: "Bellflower ",
picture: "images/bellflower.jpg"
},
{ title: "Butter ",
picture: "images/butter.jpg"
},
{ title: "Bunraku ",
picture: "images/bunraku.jpg"
},
{ title: "Cars 2 ",
picture: "images/cars2.jpg"
},
{ title: "Cost Of A Soul",
picture: "images/costofasoul.jpg"
},
{ title: "Carnage ",
picture: "images/carnage.jpg"
},
{ title: "Crazy Stupid Love ",
picture: "images/crazystupidlove.jpg"
},
{ title: "Cracks ",
picture: "images/cracks.jpg"
},
{ title: "Colombiana ",
picture: "images/colombiana.jpg"
},
{ title: "Cedar Rapids ",
picture: "images/cedarrapids.jpg"
},
{ title: "Captain America ",
picture: "images/captainamerica.jpg"
},
];
var dataList = new WinJS.Binding.List(movieArray);
Creating ListView
We have
created a data source and now let us go ahead and create a ListView. In
the ListView we need to set the itemDataSource to
MovieData.itemList.dataSource.
If you
remember, while creating a data source we have created a public namespace with
the name MovieData. In the MovieData.js file we need to add a reference as
below:
At this point if we run the application; we will
get output as below. Essentially the following is the same array we get as
output when we created the data source.
Now we need to create a template to render the movie
image and the name of the movie. An ItemTemplate for the ListView can be created
as below:
Inside the ItemTemplate there are
two controls:
- Image control to render the thumbnail of the movie
- Inside the div rendering the title of the
movie
Now go ahead and set the itemTemplate of the
ListView as below.
At this point if we run the application we should
get the ListView as below.
Notice that WinJS has automatically added a
scrollbar. At this point we should have a HTML file as below:
Default.html
<!DOCTYPE
html>
<html>
<head>
<meta
charset="utf-8">
<title>ListViewBinding</title>
<!-- WinJS references -->
<link
href="//Microsoft.WinJS.0.6/css/ui-dark.css"
rel="stylesheet">
<script
src="//Microsoft.WinJS.0.6/js/base.js"></script>
<script
src="//Microsoft.WinJS.0.6/js/ui.js"></script>
<!-- ListViewBinding references -->
<link
href="/css/default.css"
rel="stylesheet">
<script
src="/js/default.js"></script>
<script
src="/js/moviedata.js"></script>
</head>
<body>
<div
id="headerTemplate"
data-win-control="WinJS.Binding.Template"
style="display:
none">
<div
class="simpleHeaderItem">
<h1
data-win-bind="innerText: title"></h1>
</div>
</div>
<div
id="moviesTemplate"
data-win-control="WinJS.Binding.Template">
<div
style="width:
150px;
height:
130px;">
<img
src="#"
style="width:
100px;
height:
100px;"
data-win-bind="alt:
title; src: picture"
/>
<div>
<h4
data-win-bind="innerText:title"></h4>
</div>
</div>
</div>
<div
id="movieListView"
data-win-control="WinJS.UI.ListView"
data-win-options="{
itemDataSource :MovieData.itemList.dataSource,
itemTemplate:moviesTemplate,
layout: {type:
WinJS.UI.GridLayout} }">
</div>
</body>
</html>
Customizing
ListView
If we see
the ListView, it is not that immersive. We can customize a
ListView by overriding the CSS. Each HTML file has a corresponding CSS
file associated withit. For example for the default.html there is a CSS file
default.css. Now let us go ahead and override the ListView properties. In
the following CSS:
- ListView height and width is set to 600 pixels and
800 pixels respectively
- ListView border is set to 2 Pixel
- Margin of each item in ListView is set to 10
Pixel
- On hover, each item's color will be changed to
Red
We need to
put the above CSS in default.css. After that when we run the
application, we will get the ListView as below. Notice that on mouse hover the
color changes to Red.
Grouping of ListView Items
To group
the items in ListView, we need to call CreateGrouped JavaScript function
from base.js. This function is defined as below.
We can see
that it takes three parameters. An explanation of the parameters are given
below.
- groupKey : A function that accepts a single
argument. The function is called with each element in the list; the function
should return a string representing the group containing the element.
- groupData : A function that accepts a
single argument. The function is called on an element in the list for each
group. It should return the value that should be set as the data of the .groups
list element for this group.
- groupSorter : A function that
accepts two arguments. The function is called with the key of groups found in
the list. It must return one of the following numeric values: negative if the
first argument is less than the second, zero if the two arguments are
equivalent, positive if the first argument is greater than the second. If
omitted, the groups are sorted in ascending, ASCII character
order.
As you see,
the createGrouped function takes three functions as input parameters. So
let us create these functions one by one.
The following
function will compare the groups. This function will be
groupSorter.
This
function will return the group of the item.
The following
function will return the Title of the group. In this case items would be grouped
with the first letter.
In the last step we
need to call the above three functions to create a group and make a public
namespace for this; that is, it is accessible from other files.
By putting all
codes together in the mymoviedata.js file you will have two public
namespaces. You need to set MovieGroupedData as the datasource of
the ListView to create grouped data.
MovieGroupedData.js
(function ()
{
"use
strict";
//
http://www.allmoviephoto.com/photo/index_2011.html
var
movieArray = [
{ title: "The
Artist",
picture: "images/TheArtist.jpg"
},
{ title: "A
Better Life",
picture: "images/abetterlife.jpg"
},
{ title: "Abduction",
picture: "images/abduction.jpg"
},
{ title: "African Cats",
picture: "images/africancats.jpg"
},
{ title: "Angel Crest",
picture: "images/angelscrest.jpg"
},
{ title: "Arthur",
picture: "images/arthur.jpg"
},
{ title: "Anonymous",
picture: "images/anonymous.jpg"
},
{ title: "A
Dangerous Method",
picture: "images/adangerousmethod.jpg"
},
{ title: "A
Good Old Fashioned Orgy ",
picture: "images/agoodoldfashionedorgy.jpg"
},
{ title: "A
Seperation ",
picture: "images/aseparation.jpg"
},
{ title: "Another Earth ",
picture: "images/anotherearth.jpg"
},
{ title: "A
Heartbeat Away ",
picture: "images/aheartbeataway.jpg"
},
{ title: "Bad
Teacher ",
picture: "images/badteacher.jpg"
},
{ title: "Begineers ",
picture: "images/beginners.jpg"
},
{ title: "Brotherhood ",
picture: "images/brotherhood.jpg"
},
{ title: "Bridesmaids ",
picture: "images/bridesmaids.jpg"
},
{ title: "Born To Be Wild ",
picture: "images/borntobewild.jpg"
},
{ title: "Blackthorn ",
picture: "images/blackthorn.jpg"
},
{ title: "Bellflower ",
picture: "images/bellflower.jpg"
},
{ title: "Butter ",
picture: "images/butter.jpg"
},
{ title: "Bunraku ",
picture: "images/bunraku.jpg"
},
{ title: "Cars 2 ",
picture: "images/cars2.jpg"
},
{ title: "Cost Of A Soul",
picture: "images/costofasoul.jpg"
},
{ title: "Carnage ",
picture: "images/carnage.jpg"
},
{ title: "Crazy Stupid Love ",
picture: "images/crazystupidlove.jpg"
},
{ title: "Cracks ",
picture: "images/cracks.jpg"
},
{ title: "Colombiana ",
picture: "images/colombiana.jpg"
},
{ title: "Cedar Rapids ",
picture: "images/cedarrapids.jpg"
},
{ title: "Captain America ",
picture: "images/captainamerica.jpg"
},
];
var
dataList = new
WinJS.Binding.List(movieArray);
function
compareGroups(left, right) {
return
left.charCodeAt(0) - right.charCodeAt(0);
}
function
getGroupKey(dataItem) {
return
dataItem.title.toUpperCase().charAt(0);
}
function
getGroupData(dataItem) {
return
{
title: dataItem.title.toUpperCase().charAt(0)
};
}
var
publicMembers =
{
itemList: dataList
};
WinJS.Namespace.define("MovieData",
publicMembers);
var
groupedItemsList = dataList.createGrouped(getGroupKey, getGroupData,
compareGroups);
WinJS.Namespace.define("MovieGroupedData",
{
groupedItemsList:
groupedItemsList
});
})();
At this point we
have created functions to group data. Next we need to modify the ListView
datasource to group ListView items. For that let us create a header template.
Header template will display the Title of the group. The Header Template
can be created in the same way of the Item Template. The Header template is
given below:
And we have already
created the Item Template as in the following:
To group items in
the ListView we need to create a Header Template and Item Template. We have
created them in the previous step. Next we need to set the datasource of the
ListView to bind the grouped items. The ListView can be created as following for
the grouped items:
If we put all the
code together then default.html will have the following
code:
Default.html
<!DOCTYPE
html>
<html>
<head>
<meta
charset="utf-8">
<title>ListViewBinding</title>
<!-- WinJS references -->
<link
href="//Microsoft.WinJS.0.6/css/ui-dark.css"
rel="stylesheet">
<script
src="//Microsoft.WinJS.0.6/js/base.js"></script>
<script
src="//Microsoft.WinJS.0.6/js/ui.js"></script>
<!-- ListViewBinding references -->
<link
href="/css/default.css"
rel="stylesheet">
<script
src="/js/default.js"></script>
<script
src="/js/moviedata.js"></script>
</head>
<body>
<div
id="headerTemplate"
data-win-control="WinJS.Binding.Template"
style="display:
none">
<div
class="simpleHeaderItem">
<h1
data-win-bind="innerText: title"></h1>
</div>
</div>
<div
id="moviesTemplate"
data-win-control="WinJS.Binding.Template">
<div
style="width:
150px;
height:
130px;">
<img
src="#"
style="width:
100px;
height:
100px;"
data-win-bind="alt:
title; src: picture"
/>
<div>
<h4
data-win-bind="innerText:title"></h4>
</div>
</div>
</div>
<!--<div id="movieListView"
data-win-control="WinJS.UI.ListView"
data-win-options="{
itemDataSource :MovieData.itemList.dataSource,
itemTemplate:moviesTemplate,
layout: {type:
WinJS.UI.GridLayout} }">
</div> -->
<h1>Rate
Movies Application</h1>
<div
id="movieListView"
data-win-control="WinJS.UI.ListView"
data-win-options="{
itemDataSource :
MovieGroupedData.groupedItemsList.dataSource,
groupDataSource:
MovieGroupedData.groupedItemsList.groups.dataSource,
itemTemplate: moviesTemplate,
groupHeaderTemplate:
headerTemplate,
layout: {type: WinJS.UI.GridLayout}
}">
</div>
</body>
</html>
Let us go ahead and
run the application. We should be getting the output as in the
following:
We have grouped
items in the ListView. Next let us add a Semantic View. To add a Semantic
View you need to put the ListView inside a Semantic View control. In Semantic
Zoom we will have two views of the same ListView. We need to create a view for
the zoom out. For zoom out the Template can be created as given
below:
After creation of
the Template let us go ahead and create a ListView for the Zoom Out view.
The ItemDataSource
of the zoomed ListView is the same as of the zoomed in ListView. Now we need to
put both the ListView , Zoomed In and Zoomed out in the Semantic Zoom control.
We can put the ListView controls in the Semantic Zoom control as
below:
Now we should have
the default.html as the following:
Default.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ListViewBinding</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
<script src="//Microsoft.WinJS.0.6/js/base.js"></script>
<script src="//Microsoft.WinJS.0.6/js/ui.js"></script>
<!-- ListViewBinding
references -->
<link href="/css/default.css" rel="stylesheet">
<script src="/js/default.js"></script>
<script src="/js/moviedata.js"></script>
</head>
<body>
<div id="headerTemplate"
data-win-control="WinJS.Binding.Template"
style="display: none">
<div class="simpleHeaderItem">
<h1 data-win-bind="innerText:
title"></h1>
</div>
</div>
<div id="semanticZoomTemplate"
data-win-control="WinJS.Binding.Template"
style="display: none">
<div class="semanticZoomItem">
<h1 class="semanticZoomItem-Text"
data-win-bind="innerText:
title"></h1>
</div>
</div>
<div id="moviesTemplate"
data-win-control="WinJS.Binding.Template">
<div style="width: 150px; height: 130px;">
<img src="#" style="width: 100px; height: 100px;"
data-win-bind="alt: title; src:
picture" />
<div class="a">
<h4 data-win-bind="innerText:title"></h4>
</div>
</div>
</div>
<!--<div id="movieListView"
data-win-control="WinJS.UI.ListView"
data-win-options="{
itemDataSource :MovieData.itemList.dataSource,
itemTemplate:moviesTemplate,
layout: {type:
WinJS.UI.GridLayout} }">
</div> -->
<h1>Rate Movies
Application</h1>
<!--<div id="movieListView"
data-win-control="WinJS.UI.ListView"
data-win-options="{ itemDataSource :
MovieGroupedData.groupedItemsList.dataSource,
groupDataSource:
MovieGroupedData.groupedItemsList.groups.dataSource,
itemTemplate: moviesTemplate,
groupHeaderTemplate:
headerTemplate,
layout: {type: WinJS.UI.GridLayout}
}">
</div>-->
<div id="semanticZoomDiv" data-win-control="WinJS.UI.SemanticZoom">
<div id="movieListView"
data-win-control="WinJS.UI.ListView"
data-win-options="{ itemDataSource :
MovieGroupedData.groupedItemsList.dataSource,
groupDataSource:
MovieGroupedData.groupedItemsList.groups.dataSource,
itemTemplate: moviesTemplate,
groupHeaderTemplate:
headerTemplate,
layout: {type: WinJS.UI.GridLayout}
}">
</div>
<div id="zoomedOutListView"
data-win-control="WinJS.UI.ListView"
data-win-options="{ itemDataSource:
MovieGroupedData.groupedItemsList.groups.dataSource,
itemTemplate: semanticZoomTemplate,
selectionMode:
'none',
tapBehavior:
'invoke',
swipeBehavior: 'none'
}">
</div>
</div>
</body>
</html>
Next we need to add some CSS to make it more
immersive. In default.css, we need to add the following
CSS:
.win-listview
{
height: 600px;
width: 800px;
border: 2px solid gray;
}
.win-listview .win-container {
margin: 10px;
}
.win-listview .win-container:hover {
background-color: red;
border-color: red;
}
.semanticZoomItem
{
width: 130px;
height: 130px;
background-color: rgba(38, 160, 218, 1.0);
}
.semanticZoomItem .semanticZoomItem-Text
{
padding: 10px;
line-height: 150px;
white-space: nowrap;
color: white;
}
On running we should be getting the following
output:
On tapping or
pressing of the Ctrl and arrow key you should be getting the semantic zoom view.
The Semantic Zoom View of the ListView is as in the following
image:
In this way we can
work ListView and SemanticZoom WinJS controls. In a future article we will try
to pull data from a service. I hope this article is useful. Thanks for reading.