Collections are a more powerful form of arrays. In this lesson we demonstrate an "old style" collection (pointing out its limitations) as well as several of the newer, strongly typed generic collections (List<T> and Dictionary<T1, T2>) utilizing the generics syntax.
In this lesson we demonstrate how events are utilized in the .NET Framework Class Library specific to WPF and ASP.NET Web Forms applications. In these examples, we see how C# is generated by the IDE to "wire up" a user action or application event to the code that handles that event. The point is that there's a pattern to how .NET works with events and how events drive most Graphical User Interface based applications.
In this final video, Bob talks about approaches to solving common issues that arise for new software developers, where to turn for help, how to search for answers to technical questions, how to ask for help and become part of the .NET community, how to create a personal knowledge base of books and articles, and finally provides a long term path that you can follow to learn more about developing Windows and Web applications.
The Ajax Control Toolkit is now available from NuGet. This makes it super easy to add the latest version of the Ajax Control Toolkit to any Web Forms application.
If you haven’t used NuGet yet, then you are missing out on a great tool which you can use with Visual Studio to add new features to an application. You can use NuGet with both ASP.NET MVC and ASP.NET Web Forms applications. NuGet is compatible with both Websites and Web Applications and it works with both C# and VB.NET applications.
For example, I habitually use NuGet to add the latest version of ELMAH, Entity Framework, jQuery, jQuery UI, and jQuery Templates to applications that I create. To download NuGet, visit the NuGet website at:
Imagine, for example, that you want to take advantage of the Ajax Control Toolkit RoundedCorners extender to create cross-browser compatible rounded corners in a Web Forms application. Follow these steps.
Right click on your project in the Solution Explorer window and select the option Add Library Package Reference.
In the Add Library Package Reference dialog, select the Online tab and enter AjaxControlToolkit in the search box:
Click the Install button and the latest version of the Ajax Control Toolkit will be installed.
Installing the Ajax Control Toolkit makes several modifications to your application. First, a reference to the Ajax Control Toolkit is added to your application. In a Web Application Project, you can see the new reference in the References folder:
Installing the Ajax Control Toolkit NuGet package also updates your Web.config file. The tag prefix ajaxToolkit is registered so that you can easily use Ajax Control Toolkit controls within any page without adding a @Register directive to the page.
You should do a rebuild of your application by selecting the Visual Studio menu option Build, Rebuild Solution so that Visual Studio picks up on the new controls (You won’t get Intellisense for the Ajax Control Toolkit controls until you do a build).
After you add the Ajax Control Toolkit to your application, you can start using any of the 40 Ajax Control Toolkit controls in your application (see http://www.asp.net/ajax/ajaxcontroltoolkit/samples/ for a reference for the controls).
Panel – The Panel control named pnl1 contains the content which appears with rounded corners.
ToolkitScriptManager – Every page which uses the Ajax Control Toolkit must contain a single ToolkitScriptManager. The ToolkitScriptManager loads all of the JavaScript files used by the Ajax Control Toolkit.
RoundedCornersExtender – This Ajax Control Toolkit extender targets the Panel control. It makes the Panel control appear with rounded corners. You can control the “roundiness” of the corners by modifying the Radius property.
Notice that you get Intellisense when typing the Ajax Control Toolkit tags. As soon as you type <ajaxToolkit, all of the available Ajax Control Toolkit controls appear:
When you open the page in a browser, then the contents of the Panel appears with rounded corners.
The advantage of using the RoundedCorners extender is that it is cross-browser compatible. It works great with Internet Explorer, Opera, Firefox, Chrome, and Safari even though different browsers implement rounded corners in different ways. The RoundedCorners extender even works with an ancient browser such as Internet Explorer 6.
Getting the Latest Version of the Ajax Control Toolkit
The Ajax Control Toolkit continues to evolve at a rapid pace. We are hard at work at fixing bugs and adding new features to the project. We plan to have a new release of the Ajax Control Toolkit each month.
The easiest way to get the latest version of the Ajax Control Toolkit is to use NuGet. You can open the NuGet Add Library Package Reference dialog at any time to update the Ajax Control Toolkit to the latest version.
When things go horribly wrong, and your brother dies as a result: This is a technical blog for the most part. I usually talk about all kinds of geek programmer stuff, but today is different. Today I feel that I have to take a moment and discuss the death of my brother...
Building your first Windows Metro style app using C#, C++, or Visual Basic
[This documentation is preliminary and is subject to change.]
A Windows Metro style app is an application tailored for the new
Windows user experience introduced inWindows Developer Preview. Here we
introduce the essential code and concepts you need to create a Metro
style app using C++, C#, or Visual Basic using Extensible Application
Markup Language (XAML) to define the UI, and your selected language to
write the app logic.
In this topic, we'll take a quick tour of the features that you'll
use to build Metro style apps using C++, C#, or Visual Basic. We'll
create a simple blog reader that downloads and displays data from an RSS
2.0 or Atom 1.0 feed, and see how to make an app that conveys the right
personality. We introduce concepts that are core to the development
platform, including Controls, Capabilities, Layout, Templates, and Data
Binding. By the time you complete this tutorial, you'll be prepared to
start building your own Metro style app using C++, C#, or Visual Basic.
This topic should take about 20 minutes to read; however, if you
complete each of the exercises, it may take you a little longer.
Hello World
When you create your Metro style app using C++, C#, or Visual Basic,
you typically define the UI using XAML, and write your app logic in an
associated code behind file in your selected language. You will find the
XAML UI framework for Metro style apps using C++, C#, or Visual Basic
in the Windows.UI.Xaml.* namespaces of the Windows Runtime. If you've
written apps using Windows Presentation Foundation (WPF), Silverlight,
or Silverlight for Windows Phone, you're already familiar with this
programming model and much of your experience will transfer to creating
your Metro style app using C++, C#, or Visual Basic. The example here shows the XAML that defines the UI for a simple
Hello World app and its associated code behind page. Even this simple
example shows several concepts that are important to the XAML-based
programming model, including partial classes, layout, controls,
properties, and events.
' Visual Basic
Partial Public Class MainPage
Public Sub New()
Me.InitializeComponent()
End Sub
Private Sub HelloButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
DisplayText.Text = "Hello World"
End Sub
End Class
A Hello World app is good place to start. But it doesn't take you
very far down the road to profitability, so we'll take a different path
as we explore building Metro style apps for Windows Developer Preview.
The sample app that we use to get started is a simple blog reader that
downloads and displays data from an RSS 2.0 or Atom 1.0 feed. It seems
appropriate to use the feed provided by one of several Windows team
blogs, the Developing for Windows blog, shown here.
Creating Windows Metro style apps in Visual Studio
In this section, you will learn how to:
create a new Windows Metro style project in Microsoft Visual Studio 11 Express for Windows Developer Preview.
Visual Studio is a powerful Integrated Development Environment (IDE)
for developing Windows apps. It provides source file management;
integrated build, deployment and launching support; XAML, Visual Basic,
C#, C++, graphics, and manifest editing; debugging, and more. Visual
Studio comes in several editions, but we'll use Visual Studio 11 Express
for Windows Developer Preview. You can download it for free along with
the Windows Software Development Kit (SDK) for Metro style Apps so that
you have everything you need to build, package and deploy your Metro
style apps.
To get started creating an application, you can create a new Windows Metro style project using C++, C#, or Visual Basic. Visual Studio 11 Express for Windows Developer Preview includes several templates for Windows Metro style projects that give you a head start on apps using a variety of layouts. The Windows Metro style project template provides the minimum files you need for all Windows Metro style apps.
Select File > New Project. The New Project dialog box opens.
In the Installed pane, expand Visual C++, Visual C# or Visual Basic.
Select the Windows Metro style template type.
In the center pane, select Application.
Enter a name for the project.Here's a new project being created in Visual Studio 11 Express for Windows Developer Preview.
Click OK. Your project files are created.
When you create your project, Visual Studio creates the project files and displays them in the Solution Explorer pane. Let's look at the files that the Application template creates.
File Name
File Description
AssemblyInfo (.vb or .cs)
This file contains the name
and version metadata that is embedded into the generated assembly. This
file is in C# and Visual Basic projects only.
Package.appxmanifest
This file contains metadata that describes your app, including display name, description, logos, and capabilities.
Images
These files are the default logo and splashscreen images that you can replace with your own.
App.xaml, App.xaml.* (.vb, .cs, .cpp)
These files specify app-level logic. The App class is required to display the user interface.
MainPage.xaml
This file is the default start page that you use to create the user interface.
MainPage.xaml.* (.vb, .cs, .cpp)
This is the code-behind file that contains the logic for the default start page.
MainPage.xaml.h
The header file for MainPage.xaml.cpp. This file is in C++ projects only.
pch.h, pch.cpp
Precompiled header files. These files are in C++ projects only.
Specifying app capabilities
In this section, you will learn how to:
use capabilities
specify app capabilities in the Application Manifest Designer.
A Metro style app runs in a security container with limited access to
the file system, network resources, and hardware. Whenever a user
installs an app from the Windows Store, Windows looks at the metadata in
the Package.appxmanifest file to figure out what capabilities the app
needs to function. For example, an app might need to access data from
the Internet, documents from the user's Document Library, or the user's
webcam and microphone. When the app is installed, it displays to the
user the capabilities it needs, and the user must grant permission for
it to access those resources. If the app doesn't request and receive
access to a resource it needs, it will not be allowed access to that
resource when the user runs it.
Here are some common capabilities:
Capability
Name
Description
Internet (Client)
internetClient
Allows your app to access the Internet and public networks. Most apps that require Internet access should use this capability.
Internet (Client & Server)
internetClientServer
Allows
your app to access the Internet and public networks, and allows
incoming connections from the Internet to your app. Inbound access to
critical ports is always blocked. This is a superset of the Internet
(Client) capability. You do not need to declare both.
Home/Work Networking
privateNetworkClientServer
Allows
inbound and outbound access from your app to the user's trusted
networks such as home and enterprise networks. Inbound access to
critical ports is always blocked.
Document Library Access
documentsLibrary
Allows
your app to access the user's Document Library, and to add, change, or
delete files. Your app can access only file types that it has declared
in the manifest. Your app cannot access Document Libraries on HomeGroup
computers.
Picture Library Access
picturesLibrary
Allows
your app to access the user's Picture Library, and to add, change, or
delete files. It also allows access to Picture Libraries on HomeGroup
computers, and picture file types on locally connected media servers.
Video Library Access
videosLibrary
Allows
your app to access the user's Video Library, and to add, change, or
delete files. It also allows access to Video Libraries on HomeGroup
computers, and video file types on locally connected media servers.
Music Library Access
musicLibrary
Allows
your app to access the user's Music Library, and to add, change, or
delete files. It also allows access to Music Libraries on HomeGroup
computers, and music file types on locally connected media servers.
Default Windows Credentials
defaultWindowsCredentials
Allows an app to connect to intranet resources that require domain credentials.
Shared User Certificates
sharedUserCertificates
Allows your app to access software and hardware certificates, such as smart card certificates.
Removable Storage
removableStorage
Allows
your app to access removable storage devices, such as an external hard
drive or USB flash drive, and to add, change, or delete files. Your app
can access only file types that it has declared in the manifest. Your
app can't access removable storage devices on HomeGroup computers.
Location
location
Allows your app to access the user's current location.
Microphone
microphone
Allows your app to access the user's microphone.
Webcam
webcam
Allows your app to access the user's camera.
Text Messaging
sms
Allows your app to access text messaging functionality.
Near-field Proximity
proximity
Allows your app to access the user's near-field communication (NFC) device.
To add capabilities to an app
In Solution Explorer, double-click Package.appxmanifest. The file opens in the Application Manifest Designer.
In the Application Manifest Designer, select the Capabilites tab.
Select the check box next to each capability that your app needs.
Save and close the file.
When you specify a capability, it's listed in the Package.appxmanifest.xml file under the Capabilities
element. You typically set the capabilities in the Application Manifest
Designer as we just saw, but if you right-click the file and select View Code, you can see this Capabilites element in the xml.
Getting data into an app
In this section, you will learn how to:
create a custom data class
retrieve an RSS or Atom data feed asynchronously.
Now that our app can download data from the internet, we can write
the code to get the blog feed into our app. The Developing for Windows
blog exposes the full text of its posts in both RSS and Atom form. The
blog data that we want to display in our reader app is the title,
author, date, and content from each of the latest blog posts.
To start, we need to download the data for each of the posts.
Fortunately, the Windows Runtime contains a set of classes that does a
lot of the work of processing the feed data for us. We find these
classes in the Windows.Web.Syndication
namespace. It’s possible to use these classes directly to show the data
in the UI. But in our blog reader, we will create our own data classes.
This gives us some additional flexibility and allows us to treat RSS
and Atom feeds in the same way.
Our blog reader is a simple app, so we need only two data classes.
The FeedData class holds info about the RSS or Atom feed. The FeedItem
class holds info about individual blog posts that the feed contains.
Here's the code for the FeedData and FeedItem classes.
// C#
public class FeedData
{
public string Title { get; set; }
// using System.Collections.ObjectModel;
private ObservableCollection _Items = new ObservableCollection();
public ObservableCollection Items
{
get
{
return this._Items;
}
}
}
public class FeedItem
{
public string Title { get; set; }
public string Author { get; set; }
public string Content { get; set; }
public DateTime PubDate { get; set; }
}
' Visual Basic
Public Class FeedData
Public Property Title() As String = String.Empty
' Imports System.Collections.ObjectModel
Private _Items As New ObservableCollection(Of FeedItem)()
Public ReadOnly Property Items() As ObservableCollection(Of FeedItem)
Get
Return Me._Items
End Get
End Property
End Class
Public Class FeedItem
Public Property Title() As String = String.Empty
Public Property Author() As String = String.Empty
Public Property Content() As String = String.Empty
Public Property PubDate() As DateTime
End Class
In the C++ version of the FeedData and FeedItem classes, we implement the ICustomPropertyProvider interface so that data binding works correctly in Windows Developer Preview.
// C++
//
// FeedData.h
// Declaration of the FeedData and FeedItem classes
//
#pragma once
#include "pch.h"
#include
namespace SimpleBlogReader
{
// FeedData
ref class FeedData : public Windows::UI::Xaml::Data::ICustomPropertyProvider, public Platform::IDisposable
{
public:
FeedData();
void OnPropertyChanged(Platform::String^ propertyName);
// ICustomPropertyProvider interface
virtual Windows::UI::Xaml::Data::ICustomProperty^ GetCustomProperty(Platform::String^ name);
virtual Windows::UI::Xaml::Data::ICustomProperty^ GetIndexedProperty(Platform::String^ name, Windows::UI::Xaml::Interop::TypeName typeName);
virtual Platform::String^ GetStringRepresentation();
virtual property Windows::UI::Xaml::Interop::TypeName Type { Windows::UI::Xaml::Interop::TypeName get(); }
private:
Vector
With data classes in place to hold our data, let's get back to downloading the blog feed. The Windows.Web.Syndication.SyndicationClient
class retrieves a fully parsed RSS or Atom feed, so instead of tedious
explanations about parsing XML, we can move on to more interesting
problems.
The SyndicationClient class provides only one way to
retrieve a feed, and that's asynchronously. The asynchronous programming
model is common in the Windows Runtime to help ensure that apps remain
responsive. Fortunately, much of the complexity you might expect when
using asynchronous methods has been taken care of for us.
Using await in C# and Visual Basic
Using the await keyword in C# and Visual Basic, the
code for retrieving the feed asynchronously is similar to the code we
would use to retrieve the feed synchronously. Let's take a look.
' Visual Basic
Private Async Function GetFeedAsync(FeedUriString As String) As Task
' Imports Windows.Web.Syndication
Dim Client As New SyndicationClient
Dim FeedUri As New Uri(FeedUriString)
Try
Dim Feed As SyndicationFeed = Await Client.RetrieveFeedAsync(FeedUri)
Dim FeedData As New FeedData
FeedData.Title = Feed.Title.Text
For Each Item As SyndicationItem In Feed.Items
Dim FeedItem As New FeedItem
FeedItem.Title = Item.Title.Text
FeedItem.PubDate = Item.PublishedDate.DateTime
FeedItem.Author = Item.Authors(0).Name.ToString()
If Feed.SourceFormat = SyndicationFormat.Atom10 Then
FeedItem.Content = Item.Content.Text
ElseIf Feed.SourceFormat = SyndicationFormat.Rss20 Then
FeedItem.Content = Item.Summary.Text
End If
FeedData.Items.Add(FeedItem)
Next
Me.DataContext = FeedData
ItemListView.SelectedIndex = 0
Catch Ex As Exception
' Log Error.
TitleText.Text = Ex.Message
End Try
End Function
The first thing to notice is that we added the async keyword to the method signature. You can use the await keyword only in a method that's defined as async.
' Visual Basic
Private Async Function GetFeedAsync(FeedUriString As String) As Task
Next, we call the SyndicationClient.RetrieveFeedAsync method to get the SyndicationClient that contains the RSS or Atom info that we want. The await keyword here tells the compiler to do a lot of work for us behind the scenes.
' Visual Basic
Dim Feed As SyndicationFeed = Await Client.RetrieveFeedAsync(FeedUri)
Essentially, the compiler schedules the rest of the method after this
call as a callback to be executed when the call returns. It then
immediately returns control to the calling thread, typically the UI
thread, so that the app remains responsive. When RetrieveFeedAsync
returns, the rest of the code in our method is executed. And,
importantly, it's executed in the same thread context that we made the
original call from (the UI thread), so we don't have to worry about
using a dispatcher to update the UI in this code.
After we retrieve the SyndicationFeed
with the data we want, we copy the parts we need into our FeedData and
FeedItem data classes. We then set the FeedData item as the DataContext
of the page so that we can bind our UI to it. We wrap the whole thing
in a Try… Catch block to handle any exceptions that occur while we
retrieve the feed.
We want our app to load the Developing for Windows blog automatically
when it starts. For simplicity, we can call our GetFeedAsync method
from the page constructor to do this. We pass in the URL for the Atom
feed because it includes author data that we want to show, and the RSS
feed doesn't.
// C#
public MainPage()
{
InitializeComponent();
GetFeedAsync("http://windowsteamblog.com/windows/b/developers/atom.aspx");
}
' Visual Basic
Public Sub New()
InitializeComponent()
GetFeedAsync("http://windowsteamblog.com/windows/b/developers/atom.aspx")
End Sub
// C++
MainPage::MainPage()
{
InitializeComponent();
GetFeedAsync("http://windowsteamblog.com/windows/b/developers/atom.aspx");
}
Retrieving the feed data in C++
In C++, the feed is also retrieved asynchronously. But instead of using await, we use an AsyncOperationWithProgressCompletedHandler delegate named Feed_Done. This delegate contains the feed processing code that is executed after the feed is returned.
// C++
// Decalaration in MainPage.xaml.h
void GetFeedAsync(Platform::String^ feedUriString);
void Feed_Done(Windows::Foundation::IAsyncOperationWithProgress
^);
// Implementation in MainPage.xaml.cpp
void SimpleBlogReader::MainPage::GetFeedAsync(Platform::String^ feedUriString)
{
client = ref new SyndicationClient;
auto feedOperation = client->RetrieveFeedAsync(ref new Uri(feedUriString));
feedOperation->Completed = ref new AsyncOperationWithProgressCompletedHandler
(this, &MainPage::Feed_Done);
feedOperation->Start();
}
void MainPage::Feed_Done(IAsyncOperationWithProgress^ op)
{
if(op->Status == AsyncStatus::Completed) {
auto feed = op->GetResults();
FeedData^ feedData = ref new FeedData();
feedData -> Title = feed->Title->Text;
// Used to format PubDate
auto dtf = ref new Windows::Globalization::DateTimeFormatting::DateTimeFormatter
(YearFormat::Full, MonthFormat::Numeric, DayFormat::Default, DayOfWeekFormat::None);
for(int i=0; i< feed->Items->Size; i++) {
FeedItem^ feedItem = ref new FeedItem();
feedItem->Title = feed->Items->GetAt(i)->Title->Text;
feedItem->PubDate = dtf->Format(feed->Items->GetAt(i)->PublishedDate);
feedItem->Author = feed->Items->GetAt(i)->Authors->GetAt(0)->Name;
if (feed->SourceFormat == SyndicationFormat::Atom10)
{
feedItem->Content = feed->Items->GetAt(i)->Content->Text;
}
else if (feed->SourceFormat == SyndicationFormat::Rss20)
{
feedItem->Content = feed->Items->GetAt(i)->Summary->Text;
}
feedData->Items->Append(feedItem);
}
// Bind the collection to the list
this->DataContext = feedData;
this->ItemListView->ItemsSource = feedData->Items;
this->ItemListView->SelectedIndex = 0;
}
}
Defining the app layout in XAML
In this section, you will learn:
what panels you can use to define a layout in XAML
The app layout specifies the sizing and positioning of objects in your app. To position visual objects, you must put them in a Panel control or other container object. The XAML layout system provides various Panel controls, such as Grid, Canvas, and StackPanel, that serve as containers in which you position and arrange the controls.
The XAML layout system supports both absolute layout and dynamic
layout. In an absolute layout, you position controls using explicit x-y
coordinates (for example, by using a Canvas).
In a dynamic layout, the layout container and the controls can be
automatically sized and repositioned as the app resizes (for example, by
using a StackPanel or a Grid).
In practice, you typically define the layout of your app by combining
absolute and dynamic methods, and by embedding panels within other
panels.
A typical layout that is useful for a blog reader app looks like
this, with the title at the top, a list of posts on the left, and the
content of the selected post on the right.
By default, the blank app template includes a Grid named LayoutRoot. To achieve our layout, we divide the Grid into two rows. The top row holds the blog title. In the second row, we embed another Grid, divide it into two columns, and add some more layout containers to display the blog content.
Let's look at what this XAML does in more detail. To define rows in a Grid, you add RowDefinition objects to the Grid.Rows collection. You can set properties on the RowDefinition to specify the appearance of the row. You add columns in the same way, using ColumnDefinition objects and the Grid.Columns collection.
In XAML, the row definitions looks like this:
The Height="140" property setting on the first row
definition (row 0) sets the top row to an absolute height of 100 pixels.
This height doesn't change regardless of the size of the row contents
or the application. The Height="*" setting on the second
row definition (row 1) tells the bottom row to take up whatever space is
left after row 0 has sized itself. This is often called star sizing. We
also use star sizing in the column definitions of the second Grid. The width settings of Width="2*" and Width="3*" tell the Grid to divide itself into 5 equal parts. Two parts are used for the first column, and three parts are used for the second column.
To position an element within the Grid, you set the Grid.Row and Grid.Column
attached properties on the element. Remember that the row and column
numbering is zero-based. The default value of these properties is 0, so
if you don't set anything, the element will go into the first row and
the first column.
The element embeds a Grid within the bottom row of the LayoutRoot Grid. This Grid is divided into two columns.
The element adds a ListView to the left hand column of the bottom Grid. The element adds another Grid to the right hand column of the bottom Grid. We divide this Grid into two rows. The setting Height="Auto" tells the top row to make itself as tall as it needs to be to fit its content. The bottom row uses whatever space is left.
The last part of our UI that needs a layout panel is the list of blog
posts. In this list, we need to arrange the title, author, and date as
shown here. You typically use a StackPanel when you want to automatically arrange consecutive elements in a small subsection of the UI on your page. The StackPanel
is a simple layout panel that arranges its child elements into a single
line that can be oriented horizontally or vertically. You can use the StackPanel.Orientation property to specify the direction of the child elements. The default value for the Orientation property is Orientation.Vertical. We use a StackPanel
to arrange the items in our list of blog posts. We'll see it in use in
the section, Formatting data with data templates. The XAML for the StackPanel looks like this.
Adding controls and content
In this section, you will learn how to:
add controls to an app
add text to an app
add graphics to and app
add images to an app.
Layout panels are important, but they're not very interesting without
content to put in them. You create the UI for your app by adding
controls such as buttons, lists, text, graphics, and images. The
elements you use depend on what your app does. Let's take a look at some
of the controls we can use in our Metro style app. Then we add some
controls to our blog reader to display the data we retrieved.
You can use several different kinds of controls display data from collections or a web page. The ListView, GridView, and FlipView controls display collections of data. You can use the WebView control to render HTML content.
Graphics
You can add geometric shapes to your app's UI. The Shape classes are Line, Ellipse, Rectangle, Polygon, Polyline, and Path. To create shapes, define a Geometry, and then assign Brushes to render the outline and the fill. For a Shape to be rendered to the screen, you must set a Brush to the Stroke property of the Shape to render its outline, or set a Brush to the Fill property to render its fill. The different types of brushes are SolidColorBrush, LinearGradientBrush, ImageBrush, and WebViewBrush.
This example creates an Ellipse shape with a Width of 300, a Height of 200, and a Tan SolidColorBrush as its Fill.
Images
To display an image, you can either use an Image control, or use an ImageBrush to paint an image onto another control.
The example here shows how to display an image by using the Image object. In this example, the Source property specifies the location of the image that you want to display. You can set the Source
by specifying an absolute URL (for example,
http://contoso.com/myPicture.jpg) or by specifying the URL of a file
relative to your app files.
With the ImageBrush object you can use an image to paint an area of another object. This example shows how to use an ImageBrush as the Fill of an Ellipse.
For an ImageBrush, the ImageSource property specifies the location of the image to display.
Note When you use an ImageBrush as the Fill for an Ellipse, you need a different XAML syntax than we used in the previous Ellipse example. In the previous Ellipse example, you just set the Fill property to Tan using Attribute syntax. You didn't need to specify anything about the type of Brush because the XAML parser knows how to convert the string, Tan, to the appropriate SolidColorBrush. But to specify the properties of the ImageBrush you must use an expanded XAML syntax called PropertyElement syntax. With this syntax you can set the ImageSource property on the ImageBrush.
Adding controls to the blog reader
Looking at the sketch of our blog reader UI, it's clear that we need
to display one-line text (the blog and post titles), multiline-text (the
post content), and a list of blog posts. We add TextBlock controls to display the titles, and a ListView control to display the list of blog posts. At first glance, it seems that we might use a multi-line TextBlock or RichTextBlock
to display the post content. But, when we dig deeper, we see that the
string that contains the post content is not plain text, but a string of
HTML. We don't want to display a bunch of HTML tags, which is what will
happen if we put the string in a TextBlock, so we use a WebView control to display the HTML.
With controls added, the XAML for our UI now looks like this.
Displaying data
In this section, you will learn how to:
bind data to UI
format data with templates.
Binding data to UI
In the Hello World app that we started with, we updated the text in the UI by setting the Text property of the TextBlock in this button click event handler.
Sometimes setting a Text
property in code like this works well. But to display data, you
typically use data binding to connect a data source to the UI. When you
establish a binding and the data source changes, the UI elements that
are bound to the data source can reflect changes automatically.
Similarly, changes made by the user in a UI element can be reflected in
the data source. For example, if the user edits the value in a TextBox, the binding engine automatically updates the underlying data source to reflect that change.
In the blog reader app, we show the blog title by binding the Text property of the title TextBlock to the Title property of a source object.
The title of the selected blog post is shown in the same way.
But wait! If both TextBlocks have exactly the same binding, how do they show different titles? The answer is in the DataContext that each TextBlock is bound to. The DataContext
property lets you set the default binding for an entire UI element,
including all of its child elements. Sometimes, you set the DataContext property for an entire page, and at other times, you set it for individual elements on the page. The DataContext setting at each XAML level overrides any settings at a higher level. Also, you can override any DataContext setting in effect for an individual binding by setting its Source property.
In the blog reader app, we set the DataContext for the whole page in the code behind. Remember that after retrieving the data feed, we set the DataContext with this line of code.
// C#
this.DataContext = feedData;
' Visual Basic
Me.DataContext = FeedData
// C++
this->DataContext = feedData;
The context of the first TextBlock, then, is the FeedData object, so it shows the FeedData.Title property.
How does the second TextBlock show the title of the selected blog post? The second TextBlock is within a StackPanel, as we see here.
...
Notice that the DataContext of the StackPanel is bound to the SelectedItem property of the ListView. So again the binding engine works for us behind the scenes. Whenever the selection changes in the ListView, the DataContext of the StackPanel is updated automatically to be the selected post. The DataContext of the StackPanel overrides the DataContext of the page, so the second TextBlock displays the FeedItem.Title property of the selected blog post.
Each binding has a Mode property that specifies how and when the data is updated. OneTime binding means that the value is set on the target only when the binding is first created, but never updated after that. OneWay binding means that the target is updated if the source changes. TwoWay binding means that both the target and the source are updated if either one changes. If you use OneWay or TwoWay bindings, for the binding to be notified of changes to the source object, you must implement the INotifyPropertyChanged interface.
For more info about data binding, see QuickStart: Data binding to controls.
Formatting data with a data template
Showing the data we want in the list view is slightly more complex than just setting the binding. We have the ListView bound to the Items property of the FeedData object, so the correct data is there. But if we run the app like this, the ListView doesn't know what to show, so it just calls ToString on the object it's bound to. That gives us a list of "SimpleBlogReader.FeedItem" strings like this one. Clearly, this is not what we want to show. We can make it a little better by setting the DisplayMemberPath property on the ListView.
This tells the list view to call ToString on the specified property of
the bound object, instead of on the object itself. If we set DisplayMemberPath=Title, the ListView shows a list of blog post titles.
Here we see that this is closer to what we want to show. But
what we really want is to show the title, author, and published date
for each post in the list. For that, we define a template that tells
the ListView exactly how we want the data displayed. The controls for viewing collections of data items are derived from the ItemsControl class. These controls have an ItemTemplate property that we can assign a DataTemplate to. The DataTemplate defines how our data looks.
Here's the XAML for the ListView using a DataTemplate defined inline instead of DisplayMemberPath.
Defining the bit of UI inside the DataTemplate is just like defining any other UI. We use a StackPanel to stack three TextBlocks on top of each other. We then bind the Text property of TextBlocks to the Title, Author, and PubDate properties. The default DataContext for these bindings is the object displayed in the ListView, which is a FeedItem.
Here's what the list looks like when we use a template to define it's appearance.
Formatting data with a value converter
Note The C++ version of the sample code uses a DateTimeFormatter to format the date, so the date converter in this section is shown in C# and Visual Basic only.
In ItemListView's DataTemplate, we bind the PubDate property, which is a DateTime, to a TextBlock.Text property. The binding engine automatically convertsPubDatefrom a DateTime
to a string for us. But the automatic conversion shows both the date
and the time, and we want to show only the time. To fix this, we can
create our own value converter that converts a DateTime to a string, and in it we can format the string however we want to.
To create a value converter, we create a class that implements the IValueConverter interface and then implement the Convert and ConvertBack
methods. Converters can change data from one type to another, translate
data based on cultural info, or modify other aspects of the
presentation. Here, we create a date converter that converts the date
value passed in and formats it so that it shows only the day, the month,
and the year.
// C#
public class DateConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert(object value, string targetType, object parameter, string culture)
{
DateTime dt = (DateTime)value;
// Date "7/27/2011 9:30:59 AM" returns "7/27/2011"
return dt.ToString("d");
}
public object ConvertBack(object value, string targetType, object parameter, string culture)
{
string strValue = value as string;
DateTime resultDateTime;
if (DateTime.TryParse(strValue, out resultDateTime))
{
return resultDateTime;
}
return DependencyProperty.UnsetValue;
}
}
' Visual Basic
Public Class DateConverter
Implements Windows.UI.Xaml.Data.IValueConverter
Public Function Convert(ByVal value As Object, ByVal targetType As String, ByVal parameter As Object, ByVal culture As String) _
As Object Implements Windows.UI.Xaml.Data.IValueConverter.Convert
Dim dt As DateTime = DirectCast(value, DateTime)
' Date "7/27/2011 9:30:59 AM" returns "7/27/2011"
Return dt.ToString("d")
End Function
Public Function ConvertBack(ByVal value As Object, ByVal targetType As String, ByVal parameter As Object, ByVal culture As String) _
As Object Implements Windows.UI.Xaml.Data.IValueConverter.ConvertBack
Dim StrValue As String = DirectCast(value, String)
Dim Result As Date
If DateTime.TryParse(StrValue, Result) Then
Return Result
End If
Return DependencyProperty.UnsetValue
End Function
End Class
Before we can use the DateConverter class, we must declare an
instance of it in our XAML. First, we add an XML namespace mapping at
the top of MainPage.xaml. This gives us access to classes in our project
using the declared namespace. Here, we map the SimpleBlogReader project
to the namespace "local".
xmlns:local="using:SimpleBlogReader"
We then declare an instance of DateConverter with the key dateConverter as a resource of the page.
Now we can use the DateConverter in our binding. Here's the updated binding from ItemListView's DataTemplate.
With this XAML, the binding engine uses our custom DateConverter to change a DateTime to a string. The string that it returns is formatted the way we want, with only the day, month, and year.
Tip The Convert and ConvertBack
methods also let you pass in a parameter so that you can use the same
instance of the converter with different options. For example, you can
write a formatting converter that produces different formats of data
based on the input parameter that you use. You can use the ConverterParameter of the Binding class to pass a parameter as an argument into the Convert and ConvertBack methods. The sample project for the Enhancing your first Windows Metro style app with C# or Visual Basic topic uses a modified DateConverter that demonstrates this.
Displaying HTML in a WebView
To show a blog post in our app the final step is to get the post data to show in the WebView control. The WebView control gives us a way to host HTML data within our app. But if we look at its Source property, we see that it takes a Uri for the web page to display. Our HTML data is just a string of HTML. It doesn't have a Uri that we can bind to the Source property. Luckily, there is a NavigateToString method that we can pass our string of HTML to.
To make this work, we handle the ListView's SelectionChanged event. Here's the XAML for the ListView with the SelectionChanged event added.
...
In the event handler, we cast the Selected Item to a FeedItem and get the string of HTML from the Content property. We then pass the string to the NavigateToString method.
// C#
private void ItemListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
FeedItem feedItem = (sender as ListView).SelectedItem as FeedItem;
if (feedItem != null)
{
// Navigate the WebView to the blog post content HTML string.
ContentView.NavigateToString(feedItem.Content);
}
}
' Visual Basic
Private Sub ItemListView_SelectionChanged(sender As Object, e As SelectionChangedEventArgs)
Dim FeedItem As FeedItem = TryCast(TryCast(sender, ListView).SelectedItem, FeedItem)
If FeedItem IsNot Nothing Then
' Navigate the WebView to the blog post content HTML string.
ContentView.NavigateToString(FeedItem.Content)
End If
End Sub
// C++
// Declaration in MainPage.xaml.h
void ItemListView_SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e);
// Implementation in MainPage.xaml.cpp
void SimpleBlogReader::MainPage::ItemListView_SelectionChanged
(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e)
{
FeedItem^ feedItem = safe_cast(ItemListView->SelectedItem);
if (feedItem != nullptr)
{
// Navigate the WebView to the blog post content HTML string.
ContentView->NavigateToString(feedItem->Content);
}
}
Here's what the finished app looks like when we run it.
What's next?
Congratulations! You've built your first Metro style app. What to do now? Here are some suggestions:
About the author...
Jim Walker has been at Microsoft since 1997, and has been writing
about XAML since 2007 as a Programming Writer in the Developer Division
and in Windows.