Rather than show you a simple Hello World app, which is good at teaching syntax but not much else, I’ll be building a practical app that can be used throughout the book. This allows me to progressively build on the examples and use the native features of Windows 8 in a complete system.
All kidding aside, if you want a Hello World app, see the Getting Started Guide on the Windows Developer Center at http://msdn.microsoft.com/library/windows/apps/br211386.
Microsoft’s Bing, like many popular search engines, provides a service for retrieving its results. This service has recently been migrated to the Windows Azure Marketplace and is perfect for showing the power of Windows 8 apps. It allows me to communicate with a free online service and demonstrate how to search, share, update tiles, and much more with a vast collection of images.
I’ll create a simple version first that is a single page application with a textbox and a button to execute the search. When the user clicks the search button, the app loads the results from the web service, attaches them to a listbox, and displays the results (see Figure 2-1).
Before you start building the app, let me take a moment to describe the Bing Search API so you can become familiar with the results format.
In the Preface, I outlined the steps to subscribe to the Bing Search API service on the Windows Azure Marketplace. Once you’ve subscribed for the service, you can explore the data in the API using the DataMarket service explorer. This tool is available from the Bing Search API service home page by clicking the Explore This Dataset link. Figure 2-2 shows a screenshot of the tool after searching for Trains.
This page provides you with five important pieces of information:
The available options for the Query
The resulting data format and fields
The Service root URL
The URL for current expressed query
The Primary Account Key associated to the logged in user
These items should be noted or recorded somewhere so you can refer to them throughout the remainder of the book.
In addition to providing a UI for exploring the service, the Windows Azure Marketplace provides code that can be used within your .NET application to access the data. If you navigate back to the Bing Search API landing page by clicking on the logo in the top left, you will see a link to download a .NET C# Class Library, which is a single .cs file that you can include in your application (see Figure 2-3).
The Bing Search API supports two formats at the moment. The first is an XML-based ATOM format, which will be used by the C# class that was just downloaded. In addition, the API supports a JSON format, which can easily be used by any HTML and JavaScript app. The documentation on the Windows Azure Marketplace contains more information about these formats, or you can put the URL for the current query into any web browser, providing your Primary Account Key as your username and password. This will return the results in their raw form.
If you’ve ever created a new project in Visual Studio, you already know how to get started creating Windows 8 apps. To begin, open Visual Studio 2012 on a Windows 8 machine, and select File→New→Project. Figure 2-4 shows the full list of templates available for Windows Windows 8 apps. Each language contains a similar list of templates for creating Windows 8 apps. Select Blank App (XAML) under the Visual C#→Windows Store folder, enter the name BingSimpleSearch, and click OK.
Now that you have created a new project, open Solution Explorer (View→Solution Explorer). You should see the files from Figure 2-5.
The empty application template for Windows 8 apps contains two XAML files. Both of these files contain an associated code-behind file (i.e., a file with the same name with the addition of .cs).
App.xaml is the application entry point for your project. This simple application just loads the MainPage. As an application evolves, this file can be used for initializing your application dependencies (e.g., an inversion of control container), handling tombstoning and saving of settings, and providing activation triggers.
MainPage.xaml is the primary view for the
application, and it contains no content by default. As an
application evolves, this file would likely contain a Frame
control (http://msdn.microsoft.com/en-US/library/windows/apps/windows.ui.xaml.controls.frame),
which allows your app to provide navigation between multiple pages.
It would also be used as the primary shell of the UI for your apps
global items like settings.
Open up the MainPage.xaml file and you will see
the initial XAML content provided by the template. This is where you will
be adding the TextBox
and the Button
to perform your searching. Scroll down to
the root grid (it should have a Background
set to the ApplicationPageBackgroundBrush
resource). Before
you add the textbox and the button, you are going to layout the grid’s
columns and rows as in Figure 2-6.
To do this, you need two rows and two columns. The two columns will be evenly spaced at 50% and 50%. The two rows, on the other hand, will be set up to provide only the minimum amount of space required for the textbox, and the remaining space will be allocated to the ListBox (as seen in Figure 2-6). The XAML for the grid layout definition would look like Example 2-1.
Example 2-1. Definition of Grid Layout
<Grid.RowDefinitions>
<RowDefinition
Height=
"Auto"
/>
<RowDefinition
/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition
/>
<ColumnDefinition
/>
</Grid.ColumnDefinitions>
Immediately following the row and column definitions, add a TextBox
and a Button
like in Example 2-2.
Example 2-2. TextBox
and Button
for use with search app
<TextBox
x:Name=
"SearchQuery"
/>
<Button
Content=
"Search"
Grid.Column=
"1"
Click=
"Search_Click"
/>
Notice that you are providing a name to the textbox so that it can
be accessed from the code-behind later. In addition, you need to supply
the row and column assignments only if they are not equal to 0. The
textbox is defaulted to Grid.Row="0"
and Grid.Column="0"
. On the button
there is a Click event assignment to Search_Click
, which maps to a method called
Search_Click
on the code-behind where
the Bing search code will be written (see Example 2-3). To
access the code-behind, click the arrow next to
MainPage.xaml in the Solution Explorer and open the
file MainPage.xaml.cs.
Example 2-3. Search event on the code-behind for handling the Bing web service call
private
async
void
Search_Click
(
object
sender
,
RoutedEventArgs
e
)
{
// Put webservice code here
}
Communicating with a web service may take longer than 50ms.
Because of that, WinRT requires that this be an asynchronous operation.
In .NET, you can use the new async/await
keywords. These new keywords allow
you to write your asynchronous code as if it were synchronous and the
compiler handles the transferring of data between different threads. You
will notice later in Example 2-5, the await
keyword is used to unwrap the Task<T>
object from an async method. For
example, if you have an asynchronous method that returns a Task<string>
, calling that method with
an await
keyword will result in just
a string
. Despite the fact that the
code in the example reads as a synchronous call, and debugs like one,
under the covers it’s actually triggering a continuation in which case
the method gets split into two: the code before the await and the code
after the await. For more information about the new async and await
keywords, see http://msdn.microsoft.com/en-us/library/windows/apps/hh452713.aspx.
In the previous section, I showed you the download link for the service classes provided by the Windows Azure Marketplace. Now that you’ve created your project you can add this file to your project.
In addition, you will need to add references to Microsoft.Data.OData.Metro
and Microsoft.Data.Service.Client.Metro
. To do so,
you can right-click the References in the Solution Explorer and click
Add Reference. From here, you can click the Browse button on the bottom,
navigate to C:Program Files (x86)Microsoft WCF Data
Services5.0inMetro, and select both
Microsoft.Data.OData.Metro.dll and
Microsoft.Data.Services.Client.Metro.dll. Finally,
click OK.
This file, and the references, contain everything you need to connect from a .NET application. The only thing it’s missing is support for the latest asynchronous features in .NET 4.5. To add this, create a new class called BingSearchContainerExtensions.cs. Place the code from Example 2-4 into this new file.
Example 2-4. Async extensions for BingSearchContainer
using
System.Collections.Generic
;
using
System.Data.Services.Client
;
using
System.Threading.Tasks
;
namespace
Bing
{
public
static
class
BingSearchContainerExtensions
{
public
static
Task
<
IEnumerable
<
T
>>
ExecuteAsync
<
T
>(
this
DataServiceQuery
<
T
>
query
)
{
return
Task
.
Factory
.
FromAsync
<
IEnumerable
<
T
>>(
query
.
BeginExecute
,
query
.
EndExecute
,
null
);
}
}
}
Now that the code is included and WCF Data Services are ready to
communicate with our Windows Azure Marketplace endpoint the code is very
straightforward. Example 2-5 shows the updated Search_Click
method. In this method, I created
a new BingSearchContainer
with the
Service root URL from the previous section, and
provide my Primary Account key as the Credentials
. From here, you can use one of the
many methods provided by the download service file. In this case, you
want images so you use the Image
method and supply the necessary parameters. Finally, call the new async
extension method, which executes the call to the web service and when it
completes, you can update the UI with the resulting objects.
Example 2-5. WCF Data Services call to get search results
// add 'using Bing;'
// add 'using System.Net;'
private
async
void
Search_Click
(
object
sender
,
RoutedEventArgs
e
)
{
string
accountKey
=
"<AccountKey>"
;
var
context
=
new
BingSearchContainer
(
new
Uri
(
"https://api.datamarket.azure.com/Data.ashx/Bing/Search"
));
context
.
Credentials
=
new
NetworkCredential
(
accountKey
,
accountKey
);
var
result
=
await
context
.
Image
(
this
.
SearchQuery
.
Text
,
"en-US"
,
null
,
null
,
null
,
null
).
ExecuteAsync
();
ImagesList
.
ItemsSource
=
result
.
ToList
();
}
The final piece is to bind the visual elements. In Example 2-5, you set the results to an ImagesList
ListBox
that had not been created yet. On the
ListBox
, you will need to specify a
DataTemplate
for how to visually
represent the model, which in this case is just a single image. Example 2-6 shows the ListBox
definition and should be placed in the
MainPage.xaml file directly under the search
button.
Example 2-6. ListBox with a DataTemplate for an image result
<ListBox
x:Name=
"ImagesList"
Margin=
"40"
Grid.Row=
"1"
>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel
Orientation=
"Horizontal"
>
<Image
Source=
"{Binding Thumbnail.MediaUrl}"
Width=
"100"
/>
<TextBlock
Text=
"{Binding Title}"
/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
We are also going to add two images mapped to the thumbnail and the full-size image on the right-hand column. This will give you the typical effect of an image appearing pixelated while loading and becoming sharper once the download of the full-size image completes. For this effect, stack the images on top of each other; since they are the same aspect ratio, it will show the thumbnail and then cover it up with the full-size image (see Example 2-7). Although the only requirement is that this code is at the same level as the other items in the Grid, I recommend placing this code below the ListBox.
Example 2-7. Large screen image bound to selected item of the ListBox
<Grid
Grid.Row=
"1"
Grid.Column=
"1"
>
<Image
Source=
"{Binding SelectedItem.Thumbnail.MediaUrl, ElementName=ImagesList}"
/>
<Image
Source=
"{Binding SelectedItem.MediaUrl, ElementName=ImagesList}"
/>
</Grid>
You may also notice the usage of the ElementName
binding in Example 2-7. This is telling the app to access our model through
the ListBox
’s SelectedItem
property.
Your patience is about to be rewarded. You can click Run (the play button) in Visual Studio and your app will build, deploy (install on your Windows 8 Start Screen), and launch. Now you can enter whatever search term you desire, and the ListBox will populate with the thumbnails. If you select one of the images, the full-size image will populate on the right-hand side of the screen, as shown in Figure 2-7.
This is a simple example that just creates a few controls, uses C#
to access a web service, parses the results, and then displays that data
to the user using a ListBox
control.
With the exception of the XAML controls, all of the code is written with
the .NET Profile for Windows 8 Apps. What I’d really like to do is
leverage the new features of WinRT, which are found under the Windows.*
namespace.
This app allows access to full screen images that the user may want
to download. With Windows 8 apps and WinRT there is no need to download
the file in a web browser sense, because you can write directly to the
filesystem by requesting a file using the new FileOpenPicker
. Just like the search event
handler, we need to add a button to allow the user to save the image.
Replace the XAML for the Search Button
from the earlier, with the code from Example 2-8.
Example 2-8. Save Button used to trigger the FileSavePicker
<StackPanel
Grid.Column=
"1"
Orientation=
"Horizontal"
>
<Button
Content=
"Search"
Click=
"Search_Click"
/>
<Button
Content=
"Save"
Click=
"Save_Click"
/>
<TextBlock
x:Name=
"Status"
Style=
"{StaticResource BasicTextStyle}"
/>
</StackPanel>
Basically, I’ve taken the Search Button
and wrapped it into a StackPanel
so all the elements line up in a row.
Then I added the new Save Button
, which
points to a new event handler in the code-behind. Finally, I added a new
TextBlock
to display a status when
saving the image.
To wire up the code for the Save Button
, I have to add the code in the
code-behind. Example 2-9 shows the code needed to download
the file when the Save Button
is
clicked.
Example 2-9. Event Handler for the Save Button
// add 'using System;' // add 'using Windows.Networking.BackgroundTransfer;' // add 'using Windows.Storage.Pickers;' private async void Save_Click(object sender, RoutedEventArgs e) { var image = ImagesList.SelectedItem as ImageResult; if (image == null) return; var uri = new Uri(image.MediaUrl); var filename = uri.Segments[uri.Segments.Length - 1]; var extension = System.IO.Path.GetExtension(filename); var picker = new FileSavePicker(); picker.SuggestedFileName = filename; picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; picker.FileTypeChoices.Add(extension.Trim('.').ToUpper(), new string[] { extension }); var saveFile = await picker.PickSaveFileAsync(); if (saveFile != null) { Status.Text = "Download Started"; var download = new BackgroundDownloader().CreateDownload(uri, saveFile); await download.StartAsync(); Status.Text = "Download Complete"; } }
The event handler does two basic things that use the new WinRT APIs.
First, it defines and displays the FileSavePicker
for the user to select a file.
Then it saves the file using the BackgroundDownloader
API.
I could simply call the FileSavePicker
with no arguments, but that would
require the user to create the proper file extension without providing any
hints to the user: not a very good user experience. On the other hand, I
can take the filename from the URL and provide both the name and the
extension as hints to the user. Before I created the FileSavePicker
, I took a simple approach to
parsing the filename and extensions from the URL. Now the FileSavePicker
can be created and I can specify
the suggested information. Call picker.PickSaveFileAsync()
, which launches the
FileSavePicker
UI; the user is blocked
until he selects a file or clicks cancel. In the event that the user
cancels that UI, then the saveFile
will
be null; otherwise, I can take the file and write to it.
The second part of the event handler creates a new BackgroundDownloader
and tells it to create a
new DownloadOperation
based on the URL
and the file selected from the FileSavePicker
. You can do a number of things
with this DownloadOperation
, like
support larger files, support metered connections, and provide progress
and cancellation support. In this case the images are fairly small, so
just start the download and update the Status.Text
property with a before and after
status. For more information about the BackgroundDownload
API, you can download a
sample at http://code.msdn.microsoft.com/windowsapps/Background-Transfer-Sample-d7833f61.
If you run the app again, you will see a new button to save the
image. If you perform a search, select an image, and click Save, you will
see the FileSavePicker
. The picker and
the BackgroundDownloader
are full WinRT
APIs and are specific to this new platform. This is just a taste of some
of the new APIs that are available.
If you’ve been following along, you’ve already created a nice simple app. So far we’ve created a new UI in XAML, used C# for communication over the network with a web service, and communicated with WinRT to provide direct file access based on the user’s selection. The next few chapters will expand on this information and show more examples of how to use WinRT in a number of different places.
18.216.96.94