Magazine: The Microsoft Journal For Developers
Magazine: The Microsoft Journal For Developers
magazine
Asynchronous
Programming................18, 26
magazine
Asynchronous
Programming................18, 26
DIRECTX FACTOR
Triangles and Tessellation
Charles Petzold, page 74
Terabytes of Text
KENT SHARKEY Site Manager
support “Office,” PDF, HTML, XML, ZIP, JOSHUA GOULD Art Director
.
Irene Fincher Audience Development Manager
APIs for NET, Java, C++, SQL, etc. ADVERTISING SALES: 818-674-3416/[email protected]
Dan LaBianca Vice President, Group Publisher
InfoWorld
Jeffrey S. Klein Chairman of the Board
MSDN Magazine (ISSN 1528-4859) is published monthly by 1105 Media, Inc., 9201 Oakdale Avenue,
Ste. 101, Chatsworth, CA 91311. Periodicals postage paid at Chatsworth, CA 91311-9998, and at
additional mailing offices. Annual subscription rates payable in US funds are: U.S. $35.00, International
Printed in the U.S.A. Reproductions in whole or part prohibited except by written permission. Mail
requests to “Permissions Editor,” c/o MSDN Magazine, 4 Venture, Suite 150, Irvine, CA 92618.
Legal Disclaimer: The information in this magazine has not undergone any formal testing by 1105 Media,
dtSearch products: Inc. and is distributed without any warranty expressed or implied. Implementation or use of any information
contained herein is the reader’s sole responsibility. While the information has been reviewed for accuracy,
Media Kits: Direct your Media Kit requests to Matt Morollo, VP Publishing, 508-532-1418 (phone),
Reprints: For single article reprints (in minimum quantities of 250-500), e-prints, plaques and posters contact:
Document filters also available for separate PARS International, Phone: 212-221-9595, E-mail: [email protected], www.magreprints.com/
QuickQuote.asp
licensing List Rental: This publication’s subscriber list, as well as other lists from 1105 Media, Inc., is available
for rental. For more information, please contact our list manager, Jane Long, Merit Direct. Phone: 913-
685-1301; E-mail: [email protected]; Web: www.meritdirect.com/1105
4 msdn magazine
Untitled-2 1 4/30/13 10:48 AM
CUTTING EDGE DINO ESPOSITO
Offspring of the “One ASP.NET” approach to Web development that Figure 1 Foundation of a Controller Based on ASP.NET Identity
came with Visual Studio 2013, the new ASP.NET Identity system is the public class AccountController : Controller
preferred way to handle user authentication in ASP.NET applications, {
public UserManager<ApplicationUser> UserManager { get; private set; }
whether based on Web Forms or MVC. In this column, I’ll review
the basics of ASP.NET authentication and explore the new ASP.NET public AccountController(UserManager<ApplicationUser> manager)
{
Identity system from the perspective of ASP.NET MVC 5 developers. UserManager = manager;
ASP.NET has long supported two basic types of authentication: }
Windows authentication and forms authentication. Windows public AccountController() :
authentication is seldom practical for public Web sites because this(new UserManager<ApplicationUser>(
new UserStore<ApplicationUser>(new ApplicationDbContext())))
it’s based on Windows accounts and access control list (ACL) {
tokens. Thus, it requires users to have a Windows account in the }
application’s domain, and it also assumes clients are connecting ...
from Windows-equipped machines. The other option is forms }
authentication, a widely adopted approach. Forms authentication
is based on a simple idea. For each access to a protected resource, introducing right into the framework a provider-based architecture
the application ensures the request includes a valid authentica- and the membership provider. Instead of reinventing the wheel
tion cookie. If a valid cookie is found, then the request is served as every time, you could just derive membership from the built-in
usual; otherwise, the user is redirected to a login page and asked system and override only the functions you intended to change.
to provide credentials. If these credentials are recognized as valid, The ASP.NET native membership provider is a standalone
then the application issues an authentication cookie with a given component that exposes a contracted interface. The ASP.NET
expiration policy. It’s simple and it just works. runtime, which orchestrates the authentication process, is aware
of the membership interface and can invoke whatever component
managing authentication.
typically, an existing database of users.
Does that sound like a great chunk of architecture? In the begin-
ning, nearly everybody thought so. In the long run, though, quite
Implementation of any forms authentication module can’t happen a few people who repeatedly tried to build a custom membership
without a distinct module that takes care of collecting user creden- provider started complaining about the verbosity of the interface.
tials and checking them against a database of known users. Writing Actually, the membership provider comes in the form of an inher-
this membership subsystem has been one of the key responsibilities itable base class, MembershipProvider, which includes more than
of development teams—but also one of the most annoying things 30 members marked as abstract. This means that for any new mem-
ever. Writing a membership system is not hard, per se. It mostly bership provider you wanted to create, there were at least 30 mem-
requires running a query against some sort of storage system and bers to override. Worse yet, you didn’t really need many of them
checking a user name and password. This code is boilerplate and most of the time. A simpler membership architecture was needed.
can grow fairly big as you add new authentication features such as
changing and recovering passwords, handling a changing number Introducing the Simple Membership Provider
of online users and so on. In addition, it has to be rewritten nearly To save you from the burden of creating a custom membership layer
from scratch if you change the structure of the storage or add more completely from scratch, Microsoft introduced with Visual Studio
information to the object that describes the user. Back in 2005, with 2010 SP1 another option: the simple membership API. Originally
the release of ASP.NET 2.0, Microsoft addressed this problem by available in WebMatrix and Web Pages, the simple membership
6 msdn magazine
Untitled-2 1 2/6/14 10:45 AM
API has become quite a popular way of managing authentication, than not, the main reason for having a custom membership system
especially in ASP.NET MVC. In particular, the Internet application was to circumvent structural differences between the required
template in ASP.NET MVC 4 uses the simple membership API to database format and the format of the existing database of user
support user management and authentication. credentials, which might have been in use for years.
Looking under the hood of the API, it turns out that it’s just a Clearly, this wasn’t a situation that could last forever. The commu-
wrapper on top of the classic ASP.NET membership API and its nity of developers demanded with loud voices a unified system for
SQL Server-based data stores. Simple membership lets you work membership that’s simple to use, narrowly focused and usable in the
with any data store you have and requires only that you indicate same way from within any flavor of ASP.NET. This idea weds together
which columns in the table serve as the user name and user ID. well with the One ASP.NET approach pushed by Visual Studio 2013.
and authentication.
for signing users in and out. The store manager is an instance of the
UserStore<TUser> class. Figure 1 shows the skeleton of an ASP.NET
MVC account controller class that’s based on ASP.NET Identity.
The major difference from the classic membership API is a The controller holds a reference to the authentication identity
significantly shorter list of parameters for any methods. In addi- manager, UserManager. This instance of UserManager is injected
tion, you get a lot more freedom as far as the schema of the mem- into the controller. You can use either an Inversion of Control (IoC)
bership storage is concerned. As an example of the simplified API, framework or the poor man’s alternative, the dependency injection
consider what it takes to create a new user: (DI) pattern, which uses two controllers, one of which gets a
WebSecurity.CreateUserAndAccount(username, password, default value (see Figure 1).
new { FirstName = fname, LastName = lname, Email = email });
The identity store, in turn, is injected into the authentication
You do most of the membership chores via the WebSecurity class.
identity manager, where it’s used to verify credentials. The identity
In ASP.NET MVC 4, however, the WebSecurity class expects to work
store takes the form of the UserStore<TUser> class. This class
with an extended membership provider, not a classic membership pro-
results from the composition of multiple types:
vider. The additional capabilities in an extended membership provider public class UserStore<TUser> :
are related to dealing with OAuth accounts. As a result, in ASP.NET IUserLoginStore<TUser>,
IUserClaimStore<TUser>,
MVC 4, you have two parallel routes for membership implemen- IUserRoleStore<TUser>,
tation: classic membership API using the MembershipProvider IUserPasswordStore<TUser>,
IUserSecurityStampStore<TUser>,
class and simple membership API using the ExtendedMember- IUserStore<TUser>,
shipProvider class. The two APIs are incompatible. IDisposable where TUser : IdentityUser
{
Before the arrival of Visual Studio 2013 and ASP.NET MVC 5, }
ASP.NET already offered quite a few ways to handle user authen- All interfaces implemented by UserStore<TUser> are basic
tication. With forms authentication, you could rely on classic repositories for optional user-related data such as passwords, roles,
membership, the simple membership API as defined in Web Pages claims and, of course, user data. The identity store needs to know
and a variety of custom membership systems. Consider the com- about the actual data source, though. As shown in Figure 1, the data
mon position among ASP.NET experts was that complex real-world source is injected in the UserStore class through the constructor.
applications require their own membership provider. More often Storage of users’ data is managed through the Entity Framework
Code First approach. This means you don’t strictly need to create a
Figure 2 Definition of the Default User Class in ASP.NET Identity
physical database to store your users’ credentials; you can, instead,
namespace Microsoft.AspNet.Identity.EntityFramework define a User class and have the underlying framework create the
{
public class IdentityUser : IUser most appropriate database to store such records.
{ The ApplicationDbContext class wraps up the Entity Framework
public string Id { get; }
public string UserName { get; set; } context to save users’ data. Here’s a possible definition for the
public string PasswordHash { get; set; } ApplicationDbContext class:
public string SecurityStamp { get; set; }
public ICollection<IdentityUserRole> Roles { get; private set; } public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
public ICollection<IdentityUserClaim> Claims { get; private set; } {
public ICollection<IdentityUserLogin> Logins { get; private set; } }
} Basically, the database context of ASP.NET Identity handles the
}
persistence of a given user type. The user type must implement the
8 msdn magazine Cutting Edge
Figure 3 Finalizing the Authentication Process The method SignInAsync checks the specified user name and
through an External Endpoint password against the store associated with the authentication
public async Task<ActionResult> ExternalLoginCallback(
manager. To register a user and add the user to the membership
string loginProvider, string returnUrl) database, you use code like this:
{ var user = new ApplicationUser() { UserName = model.UserName };
ClaimsIdentity id = await UserManager var result = await UserManager.CreateAsync(user, model.Password);
.Authentication if (result.Succeeded)
.GetExternalIdentityAsync(AuthenticationManager); {
await SignInAsync(user, isPersistent: false);
var result = await UserManager return RedirectToAction("Index", "Home");
.Authentication }
.SignInExternalIdentityAsync(
AuthenticationManager, id); All in all, ASP.NET Identity provides a unified API for tasks
if (result.Success) related to authentication. For example, it unifies the code required
return RedirectToLocal(returnUrl);
else if (User.Identity.IsAuthenticated) to authenticate against a proprietary database or a social network
{
result = await UserManager
OAuth-based endpoint. Figure 3 shows a fragment of the code
.Authentication you need to authenticate users against an external login engine.
.LinkExternalIdentityAsync(
id, User.Identity.GetUserId());
The code in Figure 3 gets called once the OAuth authentication
if (result.Success) (for example, against Facebook) has been completed successfully.
return RedirectToLocal(returnUrl);
else
}
}
return View("ExternalLoginFailure");
ASP.NET Identity is bound to
Visual Studio 2013, but it’s also
IUser interface or just inherit from IdentityUser. Figure 2 presents
the source code of the default IdentityUser class. expected to have an autonomous
Here’s an example of a realistic custom user class you might want
to use in your applications:
public class ApplicationUser : IdentityUser
life of its own when it comes to
{
}
public DateTime Birthdate { get; set; } future builds and releases.
The use of Entity Framework Code First is a great move here as it
makes the structure of the database a secondary point. You still need The Bottom Line
one, but to create it, you can use code based on classes. In addition, As I see things, ASP.NET Identity is an overdue solution that should
you can use Entity Framework Code First migration tools to modify have come years ago. The key issue concerning ASP.NET Identity
a previously created database as you make changes to the class behind right now is the development team is trying to come up with a
it. (For more information on this, see the “Code First Migrations” programming interface that’s generic and testable enough to last
article in the MSDN Data Developer Center at bit.ly/Th92qf.) for a long time—or at least until something newer and better shows
up in the industry.
Authenticating Users For the foreseeable future, ASP.NET Identity promises to be
ASP.NET Identity is based on the newest Open Web Interface for as good as old-fashioned membership was perceived to be a
.NET (OWIN) authentication middleware. This means the typical decade ago. Personally, I like the expressiveness of the API and the
steps of authentication (for example, creating and checking cookies) attempt to fuse together different forms of authentication—built-in
can be carried out through the abstract OWIN interfaces and not and OAuth-based, for example. Another great plus is the integra-
directly via ASP.NET/IIS interfaces. Support for OWIN requires tion with OWIN, which makes it somewhat independent from a
the account controller to have another handy property, like this: specific runtime such as IIS/ASP.NET.
private IAuthenticationManager AuthenticationManager ASP.NET Identity is bound to Visual Studio 2013, but it’s also
{ expected to have an autonomous life of its own when it comes to
get {
return HttpContext.GetOwinContext().Authentication; future builds and releases. I’ve just scratched the surface of the new
} identity API here. Stay tuned for newer builds and releases! Q
}
The IAuthenticationManager interface is defined in the
Microsoft.Owin.Security namespace. This property is import-
ant because it needs to be injected into any operation that involves DINO ESPOSITO is the author of “Architecting Mobile Solutions for the Enterprise”
(Microsoft Press, 2012) and the upcoming “Programming ASP.NET MVC 5”
authentication-related steps. Here’s a typical login method: (Microsoft Press). A technical evangelist for the .NET and Android platforms at Jet-
private async Task SignInAsync(ApplicationUser user, bool isPersistent) Brains and frequent speaker at industry events worldwide, Esposito shares his vision
{
var identity = await UserManager.CreateIdentityAsync(user, of software at software2cents.wordpress.com and on Twitter at twitter.com/despos.
DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties() {
IsPersistent = isPersistent }, identity); THANKS to the following technical expert for reviewing this article:
} Pranav Rastogi (Microsoft)
msdnmagazine.com March 2014 9
Untitled-12 2 1/27/14 3:07 PM
Untitled-12 3 1/27/14 3:04 PM
BRUNO TERKALY AND
WINDOWS AZURE INSIDER RICARDO VILLALOBOS
Azure Cloud Services Code for the gateway application, which Once a connection with the device has been established, a Network-
retrieves messages from the Service Bus queue and relays the commands Stream is defined and set to listening mode. The readBuffer variable
to the Arduino device, is included with the code download (available will contain the identifier value sent by each Arduino device:
NetworkStream deviceConnectionStream = connection.GetStream();
at msdn.microsoft.com/magazine/msdnmag0314). It’s based on the work of var readBuffer = new byte[64];
Clemens Vaster, who kindly contributed his guidance and expertise if (await deviceConnectionStream.ReadAsync(readBuffer, 0, 4) == 4)
{
to this article. His original project can be found at bit.ly/L0uK0v. int deviceId = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(readBuffer, 0));
Before we dive into this code, be sure you have Visual Studio ...
2013 installed, along with version 2.2 of the Windows Azure SDK Next, a queue is created based on the deviceId value (in case it
for .NET (bit.ly/JYXx5n). The solution includes three different projects: doesn’t exist), and a message receiver object is defined (see Figure
• ArduinoListener—contains the main WorkerRole code. 3). Then, the device queue receiver is set to asynchronous mode to
• ConsoleListener—the console version of the Arduino- pull messages (commands from the queue). This queue will store
Listener, for local testing. commands sent by mobile devices, such as a Windows Phone.
• MSDNArduinoListener—the Windows Azure deploy- When a message is received in the queue, its content is inspected and
ment project for ArduinoListener. if it matches the “ON” or “OFF” commands, the information is written
to the connection stream established
with the device (see Figure 4).
Notice that the message isn’t
removed from the queue (message.
CompleteAsync) unless the writing
operation to the device connection
stream is successful. Also, in order
to keep the connection alive, the
device is expected to send a ping
heartbeat. For this proof of concept,
we aren’t expecting confirmation from
the device when it receives the message.
In a production system, however, this
would be required to comply with the
“command” pattern.
Step 3: Deploy the Arduino-
Listener Windows Azure Project
to Cloud Services Deploying the
ArduinoListener to Windows Azure
is extremely simple. In Visual Studio
2013, right-click on the MSDN-
ArduinoListener project and
Figure 2 Creating the Windows Azure Service Bus Namespace select the Publish option. You’ll find
msdnmagazine.com March 2014 13
1&1 eCOM
NEW SELL MORE WITH A
PROFESSIONAL DESIGN.
Q Whether beginner or professional, create
your store online in a few easy steps
Q Choose from over a hundred high-quality
designs and templates between industries
Q Store links easily with an existing domain
or your new included domain (free)*
Q Whether PC, tablet or smartphone your
shop will be displayed optimally on
all devices
* Offer valid for a limited time only. Complete packages come with a 30 day money back guarantee and no minimum contract term. The $7.99 per month price reflects a 12 month
pre-payment option for the 1&1 Online Store Starter package. After 12 months, regular price of $9.99 per month applies. Some features listed are only available with package upgrade.
$7.
starting at
99
month*
Try now! 30 day money back guarantee.
Patterns for
Asynchronous
MVVM Applications:
Data Binding
Stephen Cleary
Asynchronous code using the async and await keywords As of this writing, the async and await keywords are supported
is transforming the way programs are written, and with good on a wide number of MVVM platforms: desktop (Windows
reason. Although async and await can be useful for server software, Presentation Foundation [WPF] on the Microsoft .NET Framework 4
most of the current focus is on applications that have a UI. For and higher), iOS/Android (Xamarin), Windows Store (Windows 8
such applications, these keywords can yield a more responsive UI. and higher), Windows Phone (version 7.1 and higher), Silverlight
However, it’s not immediately obvious how to use async and await (version 4 and higher), as well as Portable Class Libraries (PCLs)
with established patterns such as Model-View-ViewModel (MVVM). targeting any mix of these platforms (such as MvvmCross). The
This article is the first in a short series that will consider patterns time is now ripe for “async MVVM” patterns to develop.
for combining async and await with MVVM. I’m assuming you’re somewhat familiar with async and await
To be clear, my first article on async, “Best Practices in Asyn- and quite familiar with MVVM. If that’s not the case, there are a
chronous Programming” (msdn.microsoft.com/magazine/jj991977), was number of helpful introductory materials available online. My blog
relevant to all applications that use async/await, both client and (bit.ly/19IkogW) includes an async/await intro that lists additional
server. This new series builds on the best practices in that article resources at the end, and the MSDN documentation on async is
and introduces patterns specifically for client-side MVVM appli- quite good (search for “Task-based Asynchronous Programming”).
cations. These patterns are just patterns, however, and may not For more information on MVVM, I recommend pretty much
necessarily be the best solutions for a specific scenario. If you find anything written by Josh Smith.
a better way, let me know!
A Simple Application
This article discusses: In this article, I’m going to build an incredibly simple application,
as Figure 1 shows. When the application loads, it starts an HTTP
• Combining asynchronous programming with the MVVM pattern
request and counts the number of bytes returned. The HTTP
• Developing an asynchronous data-bound property
request may complete successfully or with an exception, and the
• Common mistakes with ViewModels application will update using data binding. The application is fully
• An approach that’s data-binding friendly responsive at all times.
Technologies discussed: First, though, I want to mention that I follow the MVVM pattern
Asynchronous Programming, MVVM
rather loosely in my own projects, sometimes using a proper
domain Model, but more often using a set of services and data
18 msdn magazine
and the “UI-agnostic code” (probably the Model and definitely all
other layers, such as services and data access).
Furthermore, all code outside the View layer (that is, the View-
Model and Model layers, services, and so on) should not depend on
any type tied to a specific UI platform. Any direct use of Dispatcher
(WPF/Xamarin/Windows Phone/Silverlight), CoreDispatcher
(Windows Store), or ISynchronizeInvoke (Windows Forms) is a
bad idea. (SynchronizationContext is marginally better, but barely.)
For example, there’s a lot of code on the Internet that does some
asynchronous work and then uses Dispatcher to update the UI; a
more portable and less cumbersome solution is to use await for
asynchronous work and update the UI without using Dispatcher.
ViewModels are the most interesting layer because they have UI
affinity but don’t depend on a specific UI context. In this series, I’ll
combine async and MVVM in ways that avoid specific UI types
while also following async best practices; this first article focuses
on asynchronous data binding.
tied to the UI context. In my applications, the ViewModel is more public static class MyStaticService
closely related to the View than the Model—and the ViewModel {
public static async Task<int> CountBytesInUrlAsync(string url)
layer is essentially an API for the entire application. The View {
literally provides just the shell of UI elements in which the actual // Artificial delay to show responsiveness.
await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false);
application exists. The ViewModel layer is conceptually a testable
UI, complete with a UI thread affinity. If your Model is an actual // Download the actual data and count it.
using (var client = new HttpClient())
domain model (not a data access layer) and there’s data binding {
between the Model and ViewModel, then the Model itself also var data = await client.GetByteArrayAsync(url).ConfigureAwait(false);
return data.Length;
has UI-thread affinity. Once you’ve identified which layers have }
UI affinity, you should be able to draw a mental line between the }
}
“UI-affine code” (View and ViewModel, and possibly the Model)
msdnmagazine.com March 2014 19
Note that this is considered a service, so it’s UI-agnostic. Because properly, just as a service should. However, this is easy to forget,
the service is UI-agnostic, it uses ConfigureAwait(false) every time especially if you (or your coworkers) don’t regularly use async.
it does an await (as discussed in my other article, “Best Practices in Consider what could happen over time as the service code is main-
Asynchronous Programming”). tained. A maintenance developer might forget a ConfigureAwait,
Let’s add a simple View and ViewModel that starts an HTTP and at that point the blocking of the UI thread would become a
request on startup. The example code uses WPF windows with deadlock of the UI thread. (This is described in more detail in my
the Views creating their ViewModels on construction. This is just previous article on async best practices.)
for simplicity; the async principles and patterns discussed in this OK, so you should use “async all the way.” However, many devel-
series of articles apply across all MVVM platforms, frameworks opers proceed to the second faulty approach, illustrated in Figure 3.
and libraries. The View for now will consist of a single main Again, if you execute this code, you’ll find that it works. The UI
window with a single label. The XAML for the main View just binds now shows immediately, with “0” in the label for a few seconds
to the UrlByteCount member: before it’s updated with the correct value. The UI is responsive, and
<Window x:Class="MainWindow" everything seems fine. However, the problem in this case is han-
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> dling errors. With an async void method, any errors raised by the
<Grid> asynchronous operation will crash the application by default. This is
<Label Content="{Binding UrlByteCount}"/>
</Grid> another situation that’s easy to miss during development and shows
</Window> up only in “weird” conditions on client devices. Even changing the
The codebehind for the main window creates the ViewModel: code in Figure 3 from async void to async Task barely improves the
public partial class MainWindow application; all errors would be silently ignored, leaving the user
{
public MainWindow() wondering what happened. Neither method of handling errors is
{ appropriate. And though it’s possible to deal with this by catching
DataContext = new BadMainViewModelA();
InitializeComponent(); exceptions from the asynchronous operation and updating other
} data-bound properties, that would result in a lot of tedious code.
}
blocking on it; by doing so, it loses all the benefits of asynchronicity. private int _urlByteCount;
If you execute the current code, you’ll see the application does public int UrlByteCount
{
nothing for a few seconds, and then the UI window springs fully get { return _urlByteCount; }
formed into view with its results already populated. The problem private set { _urlByteCount = value; OnPropertyChanged(); }
}
is the application is unresponsive, which is unacceptable for many
modern applications. The example code has a deliberate delay to public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
emphasize that unresponsiveness; in a real-world application, this {
problem might go unnoticed during development and show up only PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
in “unusual” client scenarios (such as loss of network connectivity). handler(this, new PropertyChangedEventArgs(propertyName));
Another problem with synchronous blocking is more subtle: The }
}
code is more brittle. My example service uses ConfigureAwait(false)
20 msdn magazine Async Programming
ement1); areaSerie
areaSeries
ies.A
Add(seriesElement2);
A dd(se
(s riesElement2
t2);
) areaSeries
areaSeries.Ad
Add(seriesElement3);
A d(seriesElement3); // Add series to the plot area plotArea
plotArea.Series.Add(areaSeries);
Series Add(areaSeries); //page
//page.Elemen
Elements
em ts.Add(
Add(
dd( new
ne LayoutGrid()
LayyoutGrid() ); /// Add
La Add the page elements to the page AddEA
s, 240, 0); AddEAN1
AN 3Sup
Sup5(pa
5(p ge.Eleme
ent
nts, 480, 0); Ad
ddUPCVersionA(page.Elemen
e ts, 0, 135); AddUPCVersionASup2(page.Elements, 240, 135); Ad
dddUPC
UPC
CVers
sionA
o Sup5((page.Elemen
nts,
t 480, 135); AddEAN8(page.Elements, 0,
.Elements, 480, 270);; Add
ddUUPCVersionE(pa
page.Elementts, 0, 405); AddUPCVersionESu
E p2(page.Elements, 240, 405); AddUPCVersionESup5(page
age.Ele
.Ele
lemments,
s, 48
480, 405); // Add the page
e tto the document document.Pages.Add(pa
CaptionAndRectang
a lee(eleme
ements, “EAN/JA
/JAN 13 Bar Cod
de”, x, y, 204, 99); BarCode barCode = new Ean13(“123456789012”, x, y + 21); barCode.
ode.XX+
+= (20
04 - ba
arCo
ode.GettSymbolWidth()
h ) / 2; elements.Add(barCode); } private vo
dRectangle(element
e s,, “EAN
EAN/JAN 13 Bar
ar Code,
C 2 digit supplement”, x, y, 204, 99); BarCode barCode = new Ean13Sup2(“1
2 2345
56789
678 012
1212”,
2”, x, y + 21
21);
1); barCo
ode.X
X += (204 - barCode.GetSymbolWidth()) / 2; elements.Add((barC
ts, float x, float y) { AddCa
A CaptionAndRectan
angle(elements, “EAN/JAN 13 Bar Code, 5 digit supplement”, x, y, 204, 99); BarCo
a C de barCo
arC
Code
de = new
n Ean13Su
Ean1 S p5(“12
2345
567890
01212345”, x, y + 21); barCode.X += (204 - barCode
e.Get
ddUPCVersionA(Grou
Group elemen
em ts, float x, float
floa y) { AddCaptionAndRectangle(element
e s, “UPC Version A Bar Code”, x, y, 204,
2 99);
9) Ba
B
BarrCode
C barC
bar Code = ne
ew UpcVe
pcVersionA
A(“12345678901”, x, y + 21); barCode.X += (204 - ba
arCo
ddUPCVersionAS
Sup2(
up2 Grou
oupp elements,, float
oa x, float y) { AddCaptionAndRectangle(ele
( ments, “UPC Version E Bar Code, 2 digit
git sup
supp
up lement”
nt”, x,
x y, 204, 99
9); Ba
arCod
de barC
Code = new UpcVersionASup2(“12345678
7 90112”, x,
x, y +
s.Add(barCode); } private
te vo
oid AddUPCV
PCVersi
ers onASup5(Group elements, float x, float
o y) { AddCaptionAndRectangle(ele
emment
ents, “UPC
“UPC Ver
Version E Bar Code, 5 dig
git su
upplem
ment”, x, y, 204, 99); BarCode barCode = new UpcVe
ersio
ode.GetSymbolW
Width(
dth )) / 2
2; elements.Add
Add(bar
(ba Code); } private
e voi
v d AddEAN
EAN8(Group
p elements, float x, float y) { AddC
ddCapti
tionAn
onA
n dRec
Rec
ect
ctangle(elem
ments, “EAN
N/JAN
N 8 Bar Cod
de”, x, y, 204, 99); BarCode barCode = new
n Ean8(“1234
34
g(); fileDialog.Title
le = “Op
“Open
en File
F Dialog
g”; fil
fi eDialog.Filter = “Ad
Adobe PDF
F files
es (*.pdf)
f)|*.pdf|All Files (*.*)|*.*”; if (fileDi
eDialog.
log.Sh
Show
wDiallog()
og == Dialog
gResult.OK) { pdfViewe
ewer.Op
penFile(fileDialog.FileName, “”); } Save
Sav File
F Diallog sa
av
aveF
File Dialog”; ssaveF
veFileDialo
al g.Filter = “Ado
Adobe
e PDF files (*.pdf)
f)|*.pdf|All Files (**.*)|*.*”; if (saveFileDialog.ShowD
owDialo
ialo
a g()=
g()==Dia
=Dia
Di logResul
esult .O
OK) { pdfV
fViewe
ewerr.SaveAs(saveFileDia
Dialog.FileName
e); } if (p
( dfVi
dfV ewe
wer.P
Page
WithDialog(); } else
e se { Mess
Me ageBox.S
Show(
w “P
Please open a file to printt”); } OpenFile
F Dialog fileDi
D alog
log = ne
ew Ope
penFileD
pen Dialog(); file Dialog.Tiitle = “Open File Dialo
og”; filleDialog.InitialDirec
ecto
ory = @”c:\”
:\ ; fi
fileD
leDialog
lo .Filter
ter = “All
“ F
) == DialogResul
es t.O
t.OK) { Dy
D namicPDF
FView
ewerrClass test = new
ew Dynam
D micPDFVie
ewerC
r lass(); PDF
DFPrin
Printter prin
inter
nter
er = test.OpenF
pe ileForP
orPrin
in
ntter (fileDia
(file alog.FileName); prin
nter.PrintQuie
Quiet();
() } byt
by e[] cont
contents
t =
pServices; GCH
GC and
andle gc
ch = GCHandle
d .All
Al oc
c(contents, GCH
Hand
ndleTyp
Type.Pinned
d); Int
IntPtr cont
contents
entsIntPtr =gc
ch.
ch.
h.A
AddrOfPinned
nn Obje
ect()
ct ;p
pd
df Viewer.O
.OpenB
pe ufffe
fer(co
r( ntentsIntPtr
t ,
kmark Page Eleme
lement:”, x, y); p
pageEle
ement
en s.A
Add(new Book
kmarrk(“
( Bookmarked Text”
x , x + 5, y + 20,
0 par
pare
ent
e ntOutline)); pageEl
g emen
nts.A
ts.Add (new Label(“Thiss tex
text is bookma
okmarked
okma rked.”,
”, x + 5, y + 20, 2
ageElements,
s, float
fl a x, float
at y) { // Adds
dss a circltt to the pageElleme
ents AddCaptio
onAndR
AndRecta
ectangle(pag
pag
geEle
eEl ment
men s, “Circle Page Elem
ment:
ent:”,
t:: x,, y); pageEl
geElements.A
s.Add(n
dd(new Circle(x
dd (x + 112.5f
2 ,
shLarge)); } priva
vate
te void AddF
Ad orormatted
te
edTextArrea(Group
p page
geElemen
nts, float x, floa
floatt y)
y { // A
Adds a fo
for
o mattted
d text area to
o thepageE
eElle ments strring formatt
m edHt
edHtml = “<p><
“<p <i>Dynamic</i><b>PD
b>P F</b
b>&tm
tm;
m Genera
era
ator
o v6.0 for
or or .NE
matting suppo
ort for
or text th
that appearss in the document.
t. You
Y u havve “ + “com
complet
ple
ete co
ontro
rol ovve
err 8 par
aragraph
ph properties:
p spacing befo
efore
e, spacing
g after, fir
first liine “ + “indenta
ntation, left indentati
tation, righ
r t in
ndent
ntatio
tionn, aliignment, al
alllowi
<font face=’Tim
’Times’
es’>fontt fac
f e, </fon
nt>
><font poin
o tSiz
Size=’6’>ffont “ + “size, </fon
</fon
nt><fo
<f ntt co
color
olo
llor=’FF0000
00 ’>>colo
or, </font>
><b>b
<b> old, </b
</b><
<i>italic and </i><
<u>u
underline</u>
>; “ + “and 2 line pro
opert
rties: lea
eading
ng, an
nd le
ead
ding type. Text
extArea = ne
ew Format
Form tedT
dTextA
Area(for
orrmattedH
Htm
tml, x + 5, y + 20,, 215
5, 60,, F
Font
ontFamil
mi y.He
He
elvet
lv
vetica
e ica, 9, false)
e); // Sets the indent prope
roperty fo
formatte
att dTextAre
ea.Styyle.P
Paragrap
ph.In
ndent = 18; AddC
CapttionAndRect
Rectangl
gle(pa
e(pa
e (pa
pa
ageE
geElements,
ts, “F
ageEleme
m ntts, “Fo
“Form
mattedT
dTextA
tArea Overflow
flow Text:”, x + 279
9, y); pag
geEle
ement
men s.Ad
Add(fo
Add(fo
d ormat
orm
rmat
atttedTextA
tArea)); // Create
eaan overflow formatted
ed ttextt a
area forr the
t overfl
flow textt Fo
ormattedTextArea
a ove
overflowFor
Formatt
ma edTe
Text
xtAr
tArea
ea = formatte
e
a(x + 284, y + 20);
20) ppageE
Elemen
ements.Ad
dd(o
(overfl
verflow
ow
wForm
wFo rmat
a tedTe
extArea); } priv
private
ate void A
Add
dImag
mage(Group
mag up pag
geElem
emeents, float x, float y) { /// Adds an
n image
e to th
he pa
ageElem
men
ents AddCaptionAndRe
dRectangle((pag
pageElem
ments
en
nts “Image
nts, ge
e Pag
es/DPDFLo
ogo.pn
.png”), x + 112.5
5f, y + 50f,
50f, 0.24
0.24f
4f); // Image is size
ed an
nd cente
entered
d in
n the rec
ecta
tangle ima
m ge.SetBo
B unds(215, 60); image.VAlign = VAlign.Cen
enterr; ima
age.Align
n = Align.Center; pag
geE
eElements.Ad
.Addd(imag
ge); } priv
vate void A
pageElemen
nts Ad
AddCap
dC tion
onAndRecta
angle(pag
ngle(pag
geElements,
eEle “L
Labell & PageNumbe
Page eringL
ering bel Page E
gLab Elem
ementts:”, x, y); string labelText
T = “Labels can be rottated”; strring number
mbe Text = “PageNum
mbe
eringLabels
els cont
contai
ain page num
mb
beering
xt, x + 5, y + 12,
12 22
220, 80,
0 Fontt.Time
messRom
Roman,
an, 12, TextAlign..Cen
nter);; lab
label.Ang
Ang
gle = 8; Page
eNumb
Num erin
ri gLa
gLabel pageNumLabel = new PageNumber
b ingLabel
ab (nnumb
berText, x + 5, y + 55, 220, 80, Font.TimesR
esRoman, 12,
12 TextAl
tAlig
ign.
ign
n Ce
m nts.Add(labe
me abel);
l); } private
e void AddL
dLin
ne(G p pageElemen
ne(Group nts, float x, floa
oat y)) { /// Addss a lin
ne to the
he pageE
pag lements AddCaptionAndRectangle(p
( ageEleme
e nts, “Line Pa
age Element:”, x, y); page
eElemen
nts.A
s.Add(ne
ew Line(x
x+5
5, y +
w Line(x
x + 220,
2 y + 20, x + 5, y + 80, 3,
3, RgbCo
Rg olor.Green)); } pr
priv
iva
ate void
d AddLi
A ink
nk(Group
up p
pag
pa eElement
ments, float x, float y) { // Adds a link to the pageEleme
em ntts Fo
ont font = Fo
ont.TimesRoman;; st
string text = “T
This iss a link
k to Dyna
amic
m :”, x, y); Label label = ne
ment new Lab
Label(textt, x + 5, y + 20, 215
5, 80
5, 0, fon
nt, 12, Rgb
R bColor.
or.BBlu
lue);; label.Und
Under
erline = true; Link link = new Link(x + 5, y + 20, font.
on GetTe
extWidth
h(tex
xt, 12), 12 - font.G
GetD
Descend
der(1
r(12), ne
ew Url
UrlA
lAction(“
n(“h
http
E men
Ele nts.Add(li
( nk);; } priva
p vatee vvoid
d AddPath(
ath Grroup pageElem
mentts, fl
float
oat x, floatt y) { // Ad
Adds a path
h to the pageElements ceTe.DynamicPDF.PageElement
en s.Path
h path = new
w ceTe.DynamicPD
PDF.P
F.PageElemen
men
nts.P
s.Pa
ath(
h(xx + 5, y + 20,
2 R
P s.A
Path Add(new Line
eSubPat
Pa h(x
x + 215, y + 40))); path.Su
h.S bPatths.A
Add
dd((new Curv
urve
eToSubPat
Pa h(x + 10
08, y + 80, x + 160, y + 80)); path.SubPaths.Add(new
w Curv
veSu
ubPath(x + 5, y + 40, x + 65,
6 y + 80, x + 5, y + 60))); Add
AddCCa ionA
Capt And
Add(p
path); } private
e void AddR
Rec
ctangle(Gr
G oup
p page
eElemen
nts, float
float x, float
at y)
y) ordere
e dLis
dL t = ord
deredList.GetOverFlowList(x + 5, y + 20); AddCaptionAn
AndR
Recta
ang
gle(pag
ge.Elements, “Order
r ed List
L Page
ge
e Ele
El ment
nt Ove
Ove
v rflow
rfl :”, x, y, 2
8; //
8; // Create
C an uno
ordere
ed list Unordered
nor e List unorder
e edList
er stt = ne
ew Uno
norder
rderedL
edList(x
x + 5, y + 20,
20 400, 90, Font.Helvetica, 10); unorderedList.Items.Add(
Add(“Fruits””); unordered
ere List.Items.Add(“
d “Vege
Vege
g table
es””); U
Unorde
r eredS
re
edS
d ub
bList unord
t();
(); unorderedSubList.Items.
ms.Add(“
dd((“ Citrus”); unord
ordered
eredSu
edSubLiist.Ite
emss.Ad
Add
d(“ Non
n-Citr
t us”)
s” ; Ad
AddC
CaptionAndRectangle(page.Elemen
nts, “Unordered Lis
st Page
e Elem
meent:”, x, y,
y 225, 110); Uno
n rd
dere
edSubLis
bLis
st u
unnorde
deredS
redS
d ubLi
ub st2 = uno
erredSub
bList2.Items.Add((“Po
Potato”); unorderedS
SubLis
ubLiist2.Item
ms.Ad
dd(“B
Beans”); Unor
no dere
deredSub
dSubLisst subUnorderedSubList = unordered
e SubL
S ist.Items[0]].Su
ubLists.A
AddUnorder
rde edSubList(); ssub
bUnor
UnorderedSub
dS
Sub
bList.Ite
te
ems.A
m Add
d(“Lime”); s
;<M<CFG<;=FI
List sub
bUnorderedS
SubList2
st = unorderedSubL
S bList.Items
ist. s[1].Su
ubLis
sts.A
AddUnorde
eredSu
edS bLis
bL t();
t() su
ubUnorderedSubList2.Items.Add(“Man
a go”); subUnorrdere
edS
SubList2.I
t2 tem
ms.A
Add(“Banana”);
); Un
Unord
deredS
dS
Su Lis
SubList
s sub
ubUnor
n dere
de dSubList
t();
() subU
Unordered
dSubList3.Items.Add(“Swe
Swee
w t Po
Potato””); Uno
order
d redS
SubList sub
bUnor
Uno dere
er dSub
dSubList
List4
4 = unorrderedSubList2.It
2 ems[1].S
].SubLists.AddUno
orde
ered
dSub
bList(
s ); subUn
ubU orderedSubLi
ubList
b st4.
s Ite
ems.Ad
A d(“S
Ad “Strin
ing Be
ean”)
an” ; subUno
U rde
Add(“Kid
dney Bean
ean”); x += 279; pag
a e.Eleme
ements.Ad
dd(u
d nordere
edLisst); unorderedList
Lis = unord
nordered
ere List.GetOver
e FlowList(x + 5, y + 20);
) Add
A CaptionAndRec
ctan
ngle(p
page
ag .Eleme
ents, “Unor
Unordere
dere
r d List Page
e Elem
ment Ove
ve flow:
ver flo ”, x, y, 225
oid
d Add
dTextField(Group pageElemen
dTextF me ts,, flo
float x,, flo
oat y)) { Tex
xtField txtt = new TextFi
xtF eld(“txt
“t fna
fname”, x + 20, y + 40, 120, 20); txt.Defaul
u tValue = “This is a Scrrollab
ble
e TextF
Field
d”; txt.Borde
derCol
rCol
C o or = Rgb
RgbCColo
or.B
r.Black; txt
xt ackgro
xt.BackgroundC
un o
d(txt); T
d( TextField
ex txt1 = new TextFi
Field(
ld “tx
xtf1na
f1 me”,
me” x + 175, y + 40, 120, 20); txtt1.Def
De ault
u Valu
alue = “TextField”; txt1.Password = true; txt1.MaxLength = 9; txtt1.Bo
ord
derColor = RgbCollor.Black;
or.B
B txt1.B
1.Backg
ckgroun
ou dCol
olor
or = Rgb
R Colo
Colorr.Al
Al
e ies(); pieSeries.DataLabel = da
er da;
a; plo
p tAre
Area
a.Series
rie .Add(pieS
Series
s); pieSeries.Eleme
lementss.Add(
Add(27,
27, “Website A”); pieSeries.Elements.Add
d (19, “Website B”)); pieSerries
es.Element
men s.Add(21
d(21, “W
Web
ebsi
s te
e C”);
); pieS
p eries.El
Elemen
ements[0
me ts[0
s[0].Co
s[0 ].C lor
or = a
ess.Elements[2].Color = aut
utogra
og dien
dientt3;”RgbC
RgbColo
or.Alice
eBlue; txt2.Too
.ToolTip = “Multilin
ne”; page
pageEl
Elements.Add(txt2); AddCaptionAndRectangle(pageEleme
mennts, “Tex
xtFi
Field Form
orm Pag
Pagee Elemen
Elemen
nt:”,
:”, x, yy,, 504
04, 85);
5) } priva
ate
e void
oid AddC
dComb
omb
@EKL@K@M<LJ<
C
Comb oBox(“cm
mbnam
bna e”, x + 51, y + 40, 150,
15 20); cb.B
BorderColo
or = RgbColor.Blac
Black; cb.Ba
b.Back
ckgroundColor = RgbColor.AliceBlue; cb.Font = Font.Helve
elvetica
a; cb
b.Fon
Fo tSiz
Sizze = 12; cb.I
cb.Items
temss A (“Item
tems.Add e 1”);
em ); cb.
cb.Items
tems.Add
.Add(“It
Ad (“It
( Item
em 2”); cb
d table””);
di ”) cb.Item
ms[
s[“
[“Edita
able”].Select
cted
ed = true;; c
cb.Editable = tru
ue; cb.ToolTip = “Edi
“Ed tabl
ab e Co
C mbo Box”; pageElements.Add(cb); ComboBox cb1 = new
ew Combo
omb
b Box(
B x(“cmb
mb1nam
me”, x + 303,
303, y + 40, 150, 20);
20); cb1.B
cb1 Borde
rder
derColor = R
= Font.H
Helvetic
ca; cb
cb1.FontS
nt ize = 12
2; cb1.Itemss.A
Add(“IItem 1”); cb1.Ittems.Add(“It
“Item
em 2”);
”) cb1.
cb1.It
Items.Add(“Item 3”); cb1.Items.Add(“Item 4”); cb1.Itemss.A
Add
d(“No
on-Edi
ditab
table
e”);
); c
cb1.Items[“
[“Non-
“Non-Edit
Editable
able”].S
”].Seelected = true; cb1.
1 Edita
nts.Ad
nts d(cb
(cb1); Converter.Co
C nvert(“http://www.go
goog
ogle.c
com”, “Outputt.pdf”);Convert
ve er.C
er.Conve
onvert(GetDocPath(“DocumentA.rtf”), “Output.pdf”);System.Dia
iagno
ostics
css.Pro
P ocess
ess.S
s Start(“Outp
tput.p
ut.pdf”)
pdf”);; AsyncC
As ncConverter
rt aCo
Co
onverte
nve er = new A
err(aCo
(aC nverrter_Converted); aConverter.ConversionErro
or += new Con
nversionErrorEv
ventH
tHandler(aConverter_ConversionError); aConverter.Convert(@”C:\t
C:\ em
mp\Docum
mp mentA.rtf”, @”C:\tem
ment em
mp\Ou
p\Output
tputA.pd
A.pdf”);
f”);
) aConver
v rter.
ter.Co
onvert(@”C
ve t(@”C:\temp\DocumentC.rtf”, @”C:\temp\OutputC
ver C.pdf”)); aCo
onve
erter.Convert(
e “h http://
p://www.yahoo.com”, @”C:\Temp\yahoo.pdf”); ConversionOptions
ion op
option
ns = new Conversio
ns sionOpt
nOpttions
ions(720
(720,, 720,
72 72, true); ce
eTe.D
Te. ynamicPDF
te \\o
temp output.pdf”, options); ceTe.DynamicPDF.Conve
ersion.Con
nvertter.Convert(“C:\\\te
emp\\Document2.docx”, “C:\\temp\\output.pdf”, options); string
g sam
ampl
mp eHtm
mp H mll = “<ht
h ml><
ml><body
body><p>
><p>
p This is a very simpl
m e HTML
ML strring includ
<t le border=\”1\”>
<tab 1 <tr><td>100</td><td>200</td>”” + “<ttd>3
300<
</td></tr><tr><
<td>
>400</td><td>500</td><td>600</t
< d></tr></table><
></bod
/body><
y></
</h
</
/htm
ht >”;Conve
html o version.Co
n.Co
C nver
nverter.
ter.C
ConvvertHtmlString(sa
ample
mpleHtmll, “C:\\
“C \temp\
emp\\Sam
\Sam
erName
er e”, Path.Comb
o ine(GetPath(), “LetterPortrait.pdff”)); prrintJo
ob.D
DocumentName
e = “Lett
Letter
e Portrait”; if (printJob.P
ob. rinter.Color)
r pri tJob.PrintOp
prin P ntO
n tions.Co
s. lor
o = true;
true; if (prin
(prin
ri tJob
tJo .Printer.Col
C late) printJob.P
b.P
.P
PrintOpti
Opti
p ons.
ons Co
on ollat = tru
ollate
;peXd`ZG;=Ç:fdgi\_\ej`m\G;=Jfclk`fej]fi%E<K;\m\cfg\ij
Z\K\ Jf]knXi\Ëj ;peXd`ZG;= gif[lZkj gifm`[\ i\Xc$k`d\ G;= ^\e\iXk`fe# dXe`glcXk`fe# Zfem\ij`fe#
gi`ek`e^#m`\n`e^#Xe[dlZ_dfi\%Gifm`[`e^k_\Y\jkf]Yfk_nfic[j#k_\fYa\Zkdf[\cjXi\\oki\d\cp
Õ\o`Yc\ Ylk jk`cc jlggcp k_\ i`Z_ ]\Xkli\j pfl e\\[ Xj X [\m\cfg\i% I\c`XYc\ Xe[ \]ÔZ`\ek# k_\ _`^_$
g\i]fidXeZ\ jf]knXi\ `j \Xjp kf c\Xie Xe[ lj\% @] pfl [f \eZflek\i X hl\jk`fe n`k_ Xep f] fli
NNN%;PE8D@:G;=%:FD
Zfdgfe\ekj#j`dgcpZfekXZkZ\K\Jf]knXi\Ëji\X[`cpXmX`cXYc\#`e[ljkip$c\X[`e^jlggfikk\Xd%
KIPFLIG;=JFCLK@FEJ=I<<KF;8P
K
nnn%;peXd`ZG;=%Zfd&\mXcfiZXcc/''%-*(%,''-s"(+('%..)%/-)'
n
Let’s walk through the core method NotifyTaskCompletion<T>. Note that the label content is data-bound to NotifyTask-
WatchTaskAsync. This method takes a task representing the asynchro- Completion<T>.Result, not Task<T>.Result. NotifyTaskComple-
nous operation, and (asynchronously) waits for it to complete. Note tion<T>.Result is data-binding friendly: It is not blocking, and it
that the await does not use ConfigureAwait(false); I want to return to will notify the binding when the task completes. If you run the code
the UI context before raising the PropertyChanged notifications. This now, you’ll find it behaves just like the previous example: The UI
method violates a common coding guideline here: It has an empty is responsive and loads immediately (displaying the default value
general catch clause. In this case, though, that’s exactly what I want. I of “0”) and then updates in a few seconds with the actual results.
don’t want to propagate exceptions directly back to the main UI loop; The benefit of NotifyTaskCompletion<T> is it has many other
I want to capture any exceptions and set properties so that the error properties as well, so you can use data binding to show busy
handling is done via data binding. When the task completes, the type indicators or error details. It isn’t difficult to use some of these
raises PropertyChanged notifications for all the appropriate properties. convenience properties to create a busy indicator and error
An updated ViewModel using NotifyTaskCompletion<T>
would look like this: Figure 5 MainWindow.xaml
public class MainViewModel <Window x:Class="MainWindow"
{ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
public MainViewModel() xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
{ <Window.Resources>
UrlByteCount = new NotifyTaskCompletion<int>( <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
MyStaticService.CountBytesInUrlAsync("http://www.example.com")); </Window.Resources>
} <Grid>
<!-- Busy indicator -->
public NotifyTaskCompletion<int> UrlByteCount { get; private set; } <Label Content="Loading..." Visibility="{Binding UrlByteCount.IsNotCompleted,
} Converter={StaticResource BooleanToVisibilityConverter}}"/>
This ViewModel will start the operation immediately and then <!-- Results -->
create a data-bound “watcher” for the resulting task. The View <Label Content="{Binding UrlByteCount.Result}" Visibility="{Binding
UrlByteCount.IsSuccessfullyCompleted,
data-binding code needs to be updated to bind explicitly to the Converter={StaticResource BooleanToVisibilityConverter}}"/>
result of the operation, like this:
<!-- Error details -->
<Window x:Class="MainWindow" <Label Content="{Binding UrlByteCount.ErrorMessage}" Background="Red"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Visibility="{Binding UrlByteCount.IsFaulted,
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> Converter={StaticResource BooleanToVisibilityConverter}}"/>
<Grid> </Grid>
<Label Content="{Binding UrlByteCount.Result}"/> </Window>
</Grid>
</Window>
Wrapping Up
When a code base is converted from syn-
chronous to asynchronous, usually the ser-
vice or data access components change first,
and async grows from there toward the UI.
Once you’ve done it a few times, translating a
method from synchronous to asynchronous
becomes fairly straightforward. I expect (and
hope) that this translation will be automated
by future tooling. However, when async hits
the UI, that’s when real changes are necessary.
When the UI becomes asynchronous, you
must address situations where your applica-
tions are unresponsive by enhancing their
UI design. The end result is a more respon-
sive, more modern application. “Fast and
fluid,” if you will.
This article introduced a simple type that
can be summed up as a Task<T> for data
binding. Next time, I’ll look at asynchronous
commands, and explore a concept that’s
essentially an “ICommand for async.” Then,
in the final article in the series, I’ll wrap up
by considering asynchronous services. Keep
msdnmagazine.com March 2014 23
Untitled-4 2
PLATINUM SPONSOR
SUPPORTED BY
BE
MAY
THE
CODE
magazine
WITH
00110010010100101010010101011010010101010110101001010010100101010010010101010101101010001001010101010010000100110011011100010101010
1101010010000100001100101000100100011010100101011010000101101011010101110010000101000110011010101010011100110101000110101010001101110
0010101000100101010011101011011001010101011010100101001000000110101010001001010010101011100100010101101010000100111000010111001001000
01100101010100100101010101100101010001101010001010010101001101010101001010100010010101000100100010101100110110000101010001101110010
YOU!
PRODUCED BY
1/27/14 11:18 AM
LAS VEGAS 2O14
March 10 - 14 | Planet Hollywood Resort & Casino
COMPREHENSIVE
TRAINING
DEVELOPER
FOR THE
WORLD.
Visual Studio Live! Las Vegas is part of
Visual Studio Live! is your guide Live! 360 DEV, which means you’ll have
to the .NET Development universe, access to four (4) other co-located events
at no additional cost:
featuring code-Àlled days,
networking nights and independent
education. Whether you are a .NET
developer, software architect or a
designer, Visual Studio Live!’s
multi-track events include focused,
cutting-edge education on the .NET
platform that you’ll be ready to
implement as soon as you get back
to the ofÀce.
AND INTRODUCING Web Dev Live!
vslive.com/lasvegas
Untitled-4 3 1/27/14 11:18 AM
ASYNC PROGRAMMING
Asynchronous
TCP Sockets as an
Alternative to WCF
James McCaffrey
In a Microsoft technologies environment, using Windows changes the balance, so using socket programming for asynchronous
Communication Foundation (WCF) is a common approach for client-server systems is now a more attractive option than it used
creating a client-server system. There are many alternatives to WCF, to be. This article explains how to use these new asynchronous
of course, each with its own advantages and disadvantages, including features of the .NET Framework 4.5 to create low-level, high-
HTTP Web Services, Web API, DCOM, AJAX Web technologies, performance asynchronous client-server software systems.
named pipe programming and raw TCP socket programming. But The best way to see where I’m headed is to take a look at the demo
if you take into account factors such as development effort, man- client-server system shown in Figure 1. At the top of the image
ageability, scalability, performance and security, in many situations a command shell is running an asynchronous TCP socket-based
using WCF is the most efficient approach. service that accepts requests to compute the average or minimum of
However, WCF can be extremely complicated and might be overkill a set of numeric values. In the middle part of the image is a Windows
for some programming situations. Prior to the release of the Microsoft Forms (WinForm) application that has sent a request to compute
.NET Framework 4.5, asynchronous socket programming was, the average of (3, 1, 8). Notice the client is asynchronous—after the
in my opinion, too difficult in most cases to justify its use. But request is sent, while waiting for the service to respond, the user is
the ease of using the new C# await and async language features able to click on the button labeled Say Hello three times, and the
application is responsive.
The bottom part of Figure 1 shows a Web application client in
This article discusses: action. The client has sent an asynchronous request to find the
• Setting up a TCP socket-based service minimum value of (5, 2, 7, 4). Although it’s not apparent from the
• Creating a Windows Forms application demo client screenshot, while the Web application is waiting for the service
• Creating a Web application demo client response, the application is responsive to user input.
In the sections that follow, I’ll show how to code the service, the
Technologies discussed:
WinForm client and the Web application client. Along the way I’ll
Visual Studio 2012, Microsoft .NET Framework 4.5, C# discuss the pros and cons of using sockets. This article assumes you
Code download available at: have at least intermediate-level C# programming skill, but does
msdn.microsoft.com/magazine/msdnmag0314
not assume you have deep understanding or significant experi-
ence with asynchronous programming. The code download that
26 msdn magazine
accompanies this article has the complete source code
for the three programs shown in Figure 1. I have
removed most normal error checking to keep the
main ideas as clear as possible.
BEST
BEST SELLER
SELLER ComponentOne ActiveReports 8 from $1,567.02
The award-winning .NET reporting tool for HTML5, WPF, WinForms, ASP.NET & Windows Azure.
• Create sophisticated, fast and powerful reports
• Generate flexible layouts using Section, Region and Fixed page designers
• Experience a new scalable, distributed and load balanced Enterprise-grade report server
• Utilize the just released HTML5 and touch-optimized report viewers for mobile devices
• Explore an array of data visualization options including charts, maps and more
An advantage of
In other words, the service expects the literal “method=” followed
by the string “average” or “minimum,” then an ampersand character
data-access approach.
complex parameter types can be a bit tricky sometimes.
In this demo example, the service response is simple, just a string
representation of the average or minimum of an array of numeric
values. In many custom client-server situations, you’ll have to Helper methods Average and Minimum are defined as:
design some protocol for the service response. For example, private static double Average(double[] vals)
{
double sum = 0.0;
Figure 4 The Demo Service Process and Response Methods for (int i = 0; i < vals.Length; ++i)
sum += vals[i];
private async Task Process(TcpClient tcpClient) return sum / vals.Length;
{ }
string clientEndPoint = private static double Minimum(double[] vals)
tcpClient.Client.RemoteEndPoint.ToString(); {
Console.WriteLine("Received connection request from " double min = vals[0]; ;
+ clientEndPoint); for (int i = 0; i < vals.Length; ++i)
try { if (vals[i] < min) min = vals[i];
NetworkStream networkStream = tcpClient.GetStream(); return min;
StreamReader reader = new StreamReader(networkStream); }
StreamWriter writer = new StreamWriter(networkStream);
writer.AutoFlush = true; In most situations, if you’re using a program structure similar
while (true) { to the demo service, your helper methods at this point would
string request = await reader.ReadLineAsync();
if (request != null) { connect to some data source and fetch some data. An advantage
Console.WriteLine("Received service request: " + request); of low-level services is that you have greater control over your
string response = Response(request);
Console.WriteLine("Computed response is: " + response + "\n"); data-access approach. For example, if you’re getting data from
await writer.WriteLineAsync(response); SQL, you can use classic ADO.NET, the Entity Framework or any
}
else other data access method.
break; // Client closed connection A disadvantage of a low-level approach is you must explicitly
}
tcpClient.Close(); determine how to handle errors in your system. Here, if the demo
} service is unable to satisfactorily parse the request string, instead of
catch (Exception ex) {
Console.WriteLine(ex.Message); returning a valid response (as a string), the service returns an error
if (tcpClient.Connected) message. Based on my experience, there are very few general princi-
tcpClient.Close();
} ples on which to rely. Each service requires custom error handling.
} Notice the Response method has a dummy delay:
private static string Response(string request) int delay = ((int)vals[0]) * 1000;
{ System.Threading.Thread.Sleep(delay);
string[] pairs = request.Split('&'); This response delay, arbitrarily based on the first numeric value
string methodName = pairs[0].Split('=')[1];
string valueString = pairs[1].Split('=')[1]; of the request, was inserted to slow the service down so that the
WinForm and Web application clients could demonstrate UI
string[] values = valueString.Split(' ');
double[] vals = new double[values.Length]; responsiveness while waiting for a response.
for (int i = 0; i < values.Length; ++i)
A disadvantage of a low-level
for (int i = 0; i < ipHostInfo.AddressList.Length; ++i) {
if (ipHostInfo.AddressList[i].AddressFamily ==
AddressFamily.InterNetwork)
NetworkStream networkStream = client.GetStream(); Here, the await keyword is placed in-line with the asynchronous
StreamWriter writer = new StreamWriter(networkStream);
StreamReader reader = new StreamReader(networkStream); call to SendRequest. This simplifies the calling code a bit and also al-
lows the return string to be fetched without a call to Task.Result. The
writer.AutoFlush = true;
string requestData = "method=" + method + "&" + "data=" + choice of using an inline await call or using a separate-statement await
data + "&eor"; // 'End-of-request' call will vary from situation to situation, but as a general rule of thumb,
await writer.WriteLineAsync(requestData);
string response = await reader.ReadLineAsync(); it’s better to avoid the explicit use of a Task object’s Result property.
Most of the asynchronous work is performed in the Send-
client.Close();
return response; Request method, which is listed in Figure 6. Because SendRequest
} is asynchronous, it might better be named SendRequestAsync or
catch (Exception ex) {
return ex.Message; MySendRequestAsync.
} SendRequest accepts a string representing the server name
}
and begins by resolving that name to an IP address using the
same code logic that was used in the service class constructor.
command shell (which knows where the C# compiler is), and exe- A simpler alternative is to just pass the name of the server: await
cuting the command: csc.exe /target:winexe DemoFormClient.cs. client.ConnectAsync(server, port).
Using the Visual Studio design tools, I added a ComboBox control, After the server’s IP address is determined, a TcpClient
a TextBox control, two Button controls and a ListBox control, along intelligent-socket object is instantiated and the object’s Connect-
with four Label controls. For the ComboBox control, I added strings Async method is used to send a connection request to the server.
“average” and “minimum” to the control’s Items collection property. After setting up a network StreamWriter object to send data to the
I changed the Text properties of button1 and button2 to Send Async server and a StreamReader object to receive data from the server, a
and Say Hello, respectively. Then, in design view, I double-clicked request string is created using the formatting expected by the server.
on the button1 and button2 controls to register their event handlers. The request is sent and received asynchronously and returned by
I edited the click handlers as shown in Figure 5. the method as a string.
32 msdn magazine Async Programming
CHICAGO 2O14
4
May 5 - 8 | Chicago Hilton
on
vslive.com/chicago
live long
and code
Intense Take-Home
Training for Developers,
Software Architects
and Designers
Topics include:
REGISTER BY
³ Visual Studio/.NET APRIL 2 AND
³ Windows Client (Windows 8.1/
WinRT/WPF)
SAVE $200!
³ JavaScript/HTML5 Client
³ ASP.NET
³ Cloud Computing
³ Windows Phone
³ Cross-Platform Mobile Development
³ SharePoint/OfÀce
³ SQL Server Use promo code CHTIP1
vslive.com/chicago
SUPPORTED BY PRODUCED BY
magazine
</div> THANKS to the following technical experts for their advice and for reviewing
</form> this article: Piali Choudhury (MS Research), Stephen Cleary (consultant),
</body>
Adam Eversole (MS Research) Lynn Powers (MS Research) and
</html>
Stephen Toub (Microsoft)
msdnmagazine.com March 2014 33
A S P. N E T M V C 5
A .NET Developer
Primer for Single-Page
Applications
Long Le
A majority of Microsoft .NET Framework developers explosion of different kinds of JavaScript libraries. Part of the trend
have spent most of their professional lives on the server side, coding of moving to the client side is the increasing use of single-page
with C# or Visual Basic .NET when building Web applications. Of applications (SPAs). To say that SPA development is the future
course, JavaScript has been used for simple things such as modal is an extreme understatement. SPAs are how some of the best
windows, validation, AJAX calls and so on. However, JavaScript applications on the Web offer fluid UX and responsiveness, while
(client-side code for the most part) has been leveraged as a utility minimizing payloads (traffic) and round-trips to the server.
language, and applications were largely driven from the server side.
Lately there’s been a huge trend of Web application code
migrating from the server side to the client side (browser) to meet To say that SPA development
users’ expectations for fluid and responsive UX. With this being
the case, a lot of .NET developers (especially in the enterprise) are is the future is an extreme
dealing with an extreme amount of anxiety about JavaScript best
practices, architecture, unit testing, maintainability and the recent understatement.
This article discusses:
• Steps to convert an ASP.NET MVC 5 application to a single-page In this article, I’ll address the anxieties you might experience when
application (SPA) making the transition from the server side into the SPA realm. The
• Setting up an SPA infrastructure best way to deal with these anxieties is to embrace JavaScript as a
• Adding create, read, update and delete functionality
first-class language just like any .NET language, such as C#, Visual
Basic .NET, Python and so on.
Technologies discussed:
Following are some fundamental principles of .NET development
ASP.NET MVC 5, JavaScript, Single-Page Applications, Kendo UI, that are sometimes ignored or forgotten when developing apps
RequireJS, Entity Framework, Web API, OData in JavaScript:
Code download available at: • Your code base is manageable in .NET because you’re
easyspa.codeplex.com
decisive with class boundaries and where classes actually
live within your projects.
34 msdn magazine
• You separate concerns, so you don’t 7. Update the layout navigation (menu)
have classes that are responsible for links to match the new SPA-friendly
hundreds of different things with URLs (Northwind.Web/Views/Shared/
overlapping responsibilities. _Layout.cshtml).
• You have reusable repositories, queries, After these seven steps have been carried
entities (models) and data sources. out, your Web application project structure
• You put some thought into naming should look something like Figure 1.
your classes and files so they’re I’ll show how to build an awesome SPA
more meaningful. in ASP.NET MVC with the following
• You practice good use of design patterns, JavaScript libraries, available via NuGet:
coding conventions and organization. • RequireJS (requirejs.org): This is a Java-
Because this article is for .NET developers Script file and module loader. RequireJS
who are being introduced to the SPA world, will provide #include/import/require
I’ll incorporate the least number of frame- APIs and the ability to load nested
works possible to build a manageable SPA dependencies with dependency
with sound architecture. injection (DI). The RequireJS design
approach uses the Asynchronous
Creating an SPA in Seven Key Steps Module Definition (AMD) API for
Following are seven key steps to convert a JavaScript modules, which helps to
new ASP.NET Web Application that was encapsulate pieces of code into useful
created with the out-of-the-box Visual units. It also provides an intuitive way to
Studio 2013 ASP.NET MVC template into refer to other units of code (modules).
an SPA (with references to the appropriate RequireJS modules also follow the
project files that can be found in the accom- module pattern (bit.ly/18byc2Q). A simpli-
panying code download). fied implementation of this pattern uses
1. Download and install the NuGet JavaScript functions for encapsulation.
packages RequireJS, RequireJS text You’ll see this pattern in action later as
plug-in and Kendo UI Web. Figure 1 ASP.NET MVC Project Structure all JavaScript modules will be wrapped
2. Add a configuration module within a “define” or “require” function.
(Northwind.Web/Scripts/app/main.js). Those familiar with DI and Inversion of Control (IoC)
3. Add an app module (Northwind.Web/Scripts/app/app.js). concepts can think of this as a client-side DI framework. If that’s
4. Add a router module (Northwind.Web/Scripts/app/router.js). as clear as mud at the moment, no worries—I’ll soon get into
5. Add an action and view both named Spa (Northwind. some coded illustrations where all this will make sense.
Web/Controllers/HomeController.cs and Northwind. • Text plug-in for RequireJS (bit.ly/1cd8lTZ): This will be used to
Web/Views/Home/Spa.cshtml). remotely load chunks of HTML (views) into the SPA.
6. Modify the _ViewStart.cshtml file so MVC will load • Entity Framework (bit.ly/1bKiZ9I): This is pretty self-explanatory,
views without using the _Layout.cshtml file by default and because the focus of this article is on SPA, I won’t get too
(Northwind.Web/Views/_ViewStart.cshtml). much into Entity Framework. However, if you’re new to this,
there’s plenty of documentation available.
Figure 2 RequireJS Configuration • Kendo UI Web (bit.ly/t4VkVp): This is a comprehensive JavaScript/
HTML5 framework that encompasses Web UI Widgets, Data-
require.config({
paths: {
Sources, templates, the Model-View-ViewModel (MVVM)
// Packages pattern, SPAs, styling, and so on to help deliver a responsive and
'jquery': '/scripts/jquery-2.0.3.min',
'kendo': '/scripts/kendo/2013.3.1119/kendo.web.min',
adaptive application that will look great.
'text': '/scripts/text',
'router': '/scripts/app/router' Figure 3 Registered Route Definitions and Corresponding URLs
},
shim : { Registered Route (Definition) Actual Full (Bookmarkable) URL
'kendo' : ['jquery']
}, / localhost:25061/home/spa/home/index
priority: ['text', 'router', 'app'],
jquery: '2.0.3',
/home/index localhost:25061/home/spa/#/home/index/
waitSeconds: 30 home/about
});
/home/about localhost:25061/home/spa/#/home/
require([ about/home/contact
'app' /home/contact localhost:25061/home/spa/#/home/
], function (app) {
app.initialize(); contact/customer/index
}); /customer/index localhost:25061/home/spa/#/customer/index
<link href=
(*.cshtml) pages.
<div id="app"></div>
Adding an Action for the SPA Layout (Northwind.Web/
Controllers/HomeController.cs) To create and load the Spa.cshtml
In Figure 2, the paths property contains a list of where all the view, add an action and view:
modules are located and their names. Shim is the name of a module public ActionResult Spa()
{
defined previously. The shim property includes any dependencies return View();
the module may have. In this case, you’re loading a module named }
dŚŽƵƐĂŶĚƐĂƌĞƵƐŝŶŐůĞdžƐLJƐdĞĂŵΠƚŽĐƌĞĂƚĞǁŽƌŬŇŽǁƐŽůƵƟŽŶƐĂŶĚǁĞďĂƉƉƐͲǁŝƚŚŽƵƚĐŽĚŝŶŐ͊
&ŽƌƚƵŶĞ ϱϬϬ ĐŽŵƉĂŶŝĞƐ͕ ƐƚĂƚĞ͕ ůŽĐĂů͕ K͕ ĂŶĚ ŽƚŚĞƌ ĨĞĚĞƌĂů ĂŐĞŶĐŝĞƐ ƵƐĞ dĞĂŵ ƚŽ ŵĂŶĂŐĞ ƚŚĞŝƌ ƚĂƐŬƐ͘
ĂƐŝůLJƚĂŝůŽƌdĞĂŵƚŽŵĞĞƚLJŽƵƌĞdžĂĐƚƌĞƋƵŝƌĞŵĞŶƚƐͲĞǀĞŶŝĨƚŚĞLJĐŚĂŶŐĞĚĂŝůLJ͕ǁĞĞŬůLJ͕ŽƌĞǀĞŶĞǀĞƌLJŵŝŶƵƚĞ͘
Meh, sorry!
There is only one
5HSRUWLQJŁ5LFK7H[W(GLWLQJŁ6SHOO&KHFNLQJŁ%DUFRGHV
www.textcontrol.com
US: +1 855-533-TEXT
/txtextcontrol
EU: +49 421 427 067-10
config.Routes.MapHttpRoute(
Creating MVC (OData) Web API Customer Controller (North- onChange: function (arg) {
wind.Web/Api/CustomerController.cs) Now I’ll show how to var grid = arg.sender;
lastSelectedDataItem = grid.dataItem(grid.select());
create the MVC (OData) Web API Customer controller. OData is a },
data-access protocol for the Web that provides a uniform way to query
dataSource: customerDatasource,
Figure 9 Creating the Customer (Kendo UI Observable) Model onDataBound: function (arg) {
// Check if a row was selected
define(['kendo'], if (lastSelectedDataItem == null) return;
function (kendo) { // Get all the rows
var customerModel = kendo.data.Model.define({ var view = this.dataSource.view();
id: "CustomerID", // Iterate through rows
fields: { for (var i = 0; i < view.length; i++) {
CustomerID: { type: "string", editable: false, nullable: false }, // Find row with the lastSelectedProduct
CompanyName: { title: "Company", type: "string" }, if (view[i].CustomerID == lastSelectedDataItem.CustomerID) {
ContactName: { title: "Contact", type: "string" }, // Get the grid
ContactTitle: { title: "Title", type: "string" }, var grid = arg.sender;
Address: { type: "string" }, // Set the selected row
City: { type: "string" }, grid.select(grid.table.find("tr[data-uid='" + view[i].uid + "']"));
PostalCode: { type: "string" }, break;
Country: { type: "string" }, }
Phone: { type: "string" }, }
Fax: { type: "string" }, },
State: { type: "string" } });
}
}); return indexViewModel;
return customerModel;
}); });
and manipulate data sets through CRUD operations. Using ASP.NET OData is a data-access protocol
for the Web that provides a
Web API, it’s easy to create an OData endpoint. You can control which
OData operations are exposed. You can host multiple OData endpoints
CRUD operations.
to expose Customer data from the Northwind database. Once this
is created, you can run the project, and with tools such as Fiddler
(a free Web debugger at fiddler2.com) or LINQPad, you can actually
query customer data. Creating a DataSource for the Customers Grid (North-
Configuring and Exposing OData from the Customer Table for wind.Web/Scripts/app/datasources/customersDatasource.js)
the Grid (Northwind.Web/App_Start/WebApiConfig.cs) Figure If you’re familiar with data sources from ASP.NET Web Forms,
7 configures and exposes OData from the Customer table for the grid. the concept is the same here, where you create a data source for
the Customers grid (Northwind.Web/
Scripts/app/datasources/customers-
Datasource.js). The Kendo UI Data-
Source (bit.ly/1d0Ycvd) component is an
abstraction for using local (arrays of
JavaScript objects) or remote (XML,
JSON or JSONP) data. It fully supports
CRUD data operations and provides
both local and server-side support
for sorting, paging, filtering, grouping
and aggregates.
Creating the View Model for the
Customers Grid View If you’re familiar
with MVVM from Windows Presenta-
tion Foundation (WPF) or Silverlight,
this is the same exact concept, just on
the client side (found in this project in
Northwind.Web/Scripts/ViewModels/
Customer/indexViewModel.cs). MVVM
is an architectural separation pattern
used to separate the view and its data
and business logic. You’ll see in a bit
that all the data, business logic and so
on is in the view model and that the
view is purely HTML (presentation).
Figure 10 shows the code for the
Figure 12 The Customer Grid View with MVVM Using the Index View Model Customer grid view.
LightningChart
I’ll briefly describe various components of the code in Figure 10: Now add customerModel, indexViewModel and customersData-
• onClick (helper): This method is a helper function, which source modules to your RequireJS configuration (Northwind.Web/
gets an instance of the Customer grid, the current selected Scripts/app/main.js). The code is shown in Figure 11.
row and a JSON model of the representation of the
Customer for the selected row. Figure 14 The Utility Module
• save: This saves changes when doing an inline edit define([],
of a Customer. function () {
" #$$%
"
!
&
' (
#$$%
)*
*
*
!+
'&
, (-./
magazine
Register by April 2
This May, developers, software architects,
engineers, and designers will blast off in the
and Save $200!
windy city for four days of unbiased and Use promo code VSLMAR4
cutting-edge education on the Microsoft
Platform. Live long and code with .NET gurus,
launch ideas with industry experts and rub
elbows with Microsoft stars in pre-conference
workshops, 60+ sessions and fun networking Scan the QR code to
register or for more
events – all designed to make you better at your event details.
job. Plus, explore hot topics like Web API,
jQuery, MongoDB, SQL Server Data Tools
and more!
Tracks Include:
³ Visual Studio/.NET Framework
³ ASP.NET
³ SharePoint
vslive.com/chicago
"Several of the START TIME END TIME Visual Studio Live! Pre-Conference Workshops: Monday, May 5,
presentations were 7:30 AM 9:00 AM Pre-Conference Workshop Registration
cutting edge – they 9:00 AM 6:00 PM MW01 - Workshop: Modern UX Design - Billy Hollis
wouldn’t know to
7:00 AM 8:00 AM Registration
8:00 AM 9:00 AM Keynote: To Be Announced
look for.” 9:15 AM 10:30 AM T01 - What's New in WinRT Development T02 - What's New in the Visual Studio
- Rockford Lhotka 2013 IDE
John Kilic 10:45 AM 12:00 PM T05 - What's New for XAML Windows T06 - ALM with Visual Studio 2013 and Team
Web Application Developer Store Apps - Ben Dewey Foundation Server 2013 - Brian Randell
12:00 PM 1:30 PM Lunch - Visit Exhibitors
Grand Canyon University
1:30 PM 2:45 PM T09 - Interaction Design Principles and T10 - What's New for Web Developers in
Patterns - Billy Hollis Visual Studio this Year? - Mads Kristensen
3:00 PM 4:15 PM T13 - Applying UX Design in XAML - T14 - Why Browser Link Changes Things,
Billy Hollis and How You Can Write Extensions? -
Mads Kristensen
4:15 PM 4:45 PM Networking Break - Visit Exhibitors
4:45 PM 6:00 PM T17 - What's New for HTML/WinJS T18 - Katana, OWIN, and Other Awesome
Windows Store Apps - Ben Dewey Codenames: What's coming? -
Howard Dierking
6:00 PM 7:30 PM Exhibitor Welcome Reception
START TIME END TIME Visual Studio Live! Day 2: Wednesday, May 7, 2014
7:00 AM 8:00 AM Registration
8:00 AM 9:00 AM Keynote: To Be Announced
9:15 AM 10:30 AM W01 - Windows 8 HTML/JS Apps for the W02 - Creating Data-Driven Mobile Web
ASP.NET Developer - Adam Tuliper Apps with ASPNET MVC and jQuery Mobile
- Rachel Appel
10:45 AM 12:00 PM W05 - Developing Awesome 3D W06 - Getting Started with Xamarin -
Applications with Unity and Walt Ritscher
C#/JavaScript - Adam Tuliper
12:00 PM 1:30 PM Birds-of-a-Feather Lunch & Exhibitor RafÁe at 1:15pm MUST be present to win
1:30 PM 2:45 PM W09 - What's New in WPF 4.5 - W10 - Building Multi-Platform Mobile Apps
Walt Ritscher with Push NotiÀcations - Nick Landry
3:00 PM 4:15 PM W13 - Implementing M-V-VM W14 - Getting Started with Windows Phone
(Model-View-View Model) for WPF - Development - Nick Landry
Philip Japikse
4:30 PM 5:45 PM W17 - Build Maintainable Windows Store W18 - Build Your First Mobile App in 1 Hour
Apps with MVVM and Prism - Brian Noyes with Microsoft App Studio - Nick Landry
START TIME END TIME Visual Studio Live! Day 3: Thursday, May 8, 2014
7:30 AM 8:00 AM Registration
8:00 AM 9:15 AM TH01 - Leveraging Windows Azure Web TH02 - To Be Announced
Sites (WAWS) - Rockford Lhotka
9:30 AM 10:45 AM TH05 - Zero to Connected with Windows TH06 - Essential C# 6.0 - Mark Michaelis
Azure Mobile Services - Brian Noyes
11:00 AM 12:15 PM TH09 - Building Services with ASP.NET TH10 - Performance and Diagnostics Hub
MVC Web API Deep Dive - Marcel de Vries in Visual Studio 2013 - Brian Peek
12:15 PM 1:30 PM Lunch
1:30 PM 2:45 PM TH13 - Beyond Hello World: A Practical TH14 - Visual Studio 2013 Release Manager:
Introduction to Node.js on Windows Reduce Your Cycle Time to Improve Your
Azure Websites - Rick Garibay Value Delivery - Marcel de Vries
3:00 PM 4:15 PM TH17 - From the Internet of Things to TH18 - Create Automated Cross Browser
Intelligent Systems: A Developer's Testing of Your Web Applications with
Primer - Rick Garibay Visual Studio CodedUI - Marcel de Vries
4:30 PM 5:30 PM Conference Wrap-Up Panel: Andrew Brust, Miguel Castro, Rockford Lhotka, Ted Neward,
*Speakers and sessions subject to change
MW02 - Workshop: Data-Centric Single Page MW03 - Workshop: SQL Server for Developers -
Applications with Durandal, Knockout, Breeze, Andrew Brust & Leonard Lobel
and Web API - Brian Noyes
T03 - HTML5 for Better Web Sites - T04 - Introduction to Windows Azure - Vishwas Lele
Robert Boedigheimer
m T07 - Great User Experiences with CSS 3 - T08 - Windows Azure Cloud Services - Vishwas Lele
Robert Boedigheimer
T11 - Build Angular Applications Using TypeScipt - T12 - Windows Azure SQL Database – SQL Server in
Part 1 - Sergey Barskiy the Cloud - Leonard Lobel
T15 - Build Angular Applications Using TypeScipt - T16 - Solving Security and Compliance Challenges with
Part 2 - Sergey Barskiy Hybrid Clouds - Eric D. Boyd
T19 - Building Real Time Applications with ASP.NET T20 - Learning Entity Framework 6 - Leonard Lobel Visual Studio Live! Chicago Blues After Dark
SignalR - Rachel Appel
Reception at Buddy Guy's Legends
twitter.com/vslive – @VSLive
W07 - JavaScript for the C# Developer - W08 - SQL Server 2014: Features Drill-down - Scott Klein
Philip Japikse
e W15 - Knocking it Out of the Park, with Knockout. W16 - To Be Announced linkedin.com – Join the
JS - Miguel Castro “Visual Studio Live” group!
ur W19 - JavaScript: Turtles, All the Way Down - W20 - Building Apps for SharePoint - Mark Michaelis
Ted Neward
REGISTER BY APRIL 2
AND SAVE $200!
TH03 - What's New in MVC 5 - Miguel Castro TH04 - Excel, Power BI and You: An Analytics Superhub
- Andrew Brust
TH07 - What's New in Web API 2 - Miguel Castro TH08 - Big Data 101 with HDInsight - Andrew Brust
TH11 - Upgrading Your Existing ASP.NET Apps - TH12 - NoSQL for the SQL Guy - Ted Neward Use Promo Code VSLMAR4
Pranav Rastogi
: TH15 - Finding and Consuming Public Data APIs - TH16 - Git for the Microsoft Developer - Eric D. Boyd
G. Andrew Duthie
TH19 - Provide Value to Customers and TH20 - Writing Asynchronous Code Using .NET 4.5
Enhance Site Stickiness By Creating an API - and C# 5.0 - Brian Peek
G. Andrew Duthie Scan the QR code to
register or for more
d, & Brian Peek
event details.
vslive.com/chicago
Building a
Netduino-Based HID
Sensor for WinRT
Donn Morse
The Human Interface Device (HID) protocol was origi- introduced the HID Windows Runtime (WinRT) API with
nally intended to simplify the use of devices such as mice, keyboards Windows 8.1 (bit.ly/1aot1by). This new API lets you write Windows
and joysticks. However, because of its unique features—including Store apps for your device using JavaScript, Visual Basic, C# or C++.
its self-descriptive nature—device manufacturers use the protocol In addition, Microsoft recently added support for several new
to support medical devices, health and fitness devices, and custom transports, so you aren’t limited to a USB cable. Today, you can
sensors. If you’re new to the HID API, refer to the USB HID create a HID device that transmits and receives packets over USB,
Information site (bit.ly/1mbtyTz) to find more information. Another Bluetooth, Bluetooth LE, and I2C. (For more information, see “HID
great resource is Jan Axelson’s book, “USB Complete: The Devloper’s Transports” at bit.ly/1asvwg6.)
Guide, Fourth Edition” (Lakeview Research LLC, 2009). In this article, I’ll show how you can build a simple temperature
Prior to Windows 8.1, if you were writing an application for a sensor that’s compatible with the HID protocol. Then I’ll describe
HID device you wrote a native Win32 app. But if you were a Web a sample Windows Store app that can display temperature data
or a .NET developer, the ramp was steep. To address this, Microsoft from the device.
the Netduino and converts it into an output voltage proportional After you’ve upgraded the firmware on your board, you’re ready
to the current Celsius temperature. to begin constructing the temperature-sensor circuit. The first step
Here are the parts you need to build your own HID sensor: requires you to attach the RS232 shield to your board. (As I already
• Netduino 1 or Netduino Plus 1 (Amazon, amzn.to/1dvTeLh): A mentioned, the Netduino is pin-compatible with the Arduino, so if
development board with programmable microcontroller you’ve been working with the Arduino and have an RS232 shield
that supports the .NET Micro Framework. handy, you can use it.) Snap the RS232 shield onto the Netduino
• RS232 shield (CuteDigi, bit.ly/1j7uaMR): The RS232 module as shown in Figure 2.
for downloading and debugging the firmware. (This shield After you’ve attached the RS232 shield, the next step is to attach
is required for the beta version of the firmware being used.) the temperature sensor to the 5V power source, ground and pin
• LM35 Sensor (DigiKey, bit.ly/KjbQkN): The temperature sen- 0 of the Netduino. Figure 3, from the TI datasheet for the sensor,
sor that converts input voltage to output voltage based on shows the pin-outs.
the current temperature.
• RS232-to-USB converter cable (Parallax, bit.ly/1iVmP0a): The Installing the Sensor Firmware
cable for downloading the temperature-sensor firmware via There are two layers, or instances, of firmware on the Netduino.
the RS232 shield. (Note that an FTDI chipset is required The first is the manufacturer’s firmware, which includes the .NET
for compatibility with the shield.) Micro Framework; the second is your device’s firmware. The man-
• 9V 650mA power supply (Amazon, amzn.to/1d6R8LH): The ufacturer’s firmware processes requests from the device firmware.
power supply for the Netduino board. The manufacturer’s firmware is loaded once onto the development
• USB to Micro-USB cable (Amazon, amzn.to/Kjc8Ii): The board and executes each time you power up the device. In contrast,
cable for sending HID packets from the Netduino to your you typically refresh your device firmware multiple times during
Windows 8.1 tablet or laptop. the development and prototyping process.
Figure 1 shows the complete HID temperature sensor setup. In order to install any device firmware, you first need to install
The RS232 shield is attached to the top of the Netduino. The an instance of Visual C# Express 2010 on your development
breadboard contains the LM35 sensor, which is attached to 5V, machine. You’ll find a link to the download at bit.ly/1eRBed1.
ground and Pin 0. (Pin 0 is one of six analog-to-digital [ADC] pins For most Netduino projects, you can download and debug your
on the board). So, let’s get started. firmware using the native USB connection. However, the beta ver-
The firmware your Netduino 1 (or Netduino Plus 1) comes with sion of the manufacturer’s firmware requires an RS232 connection
doesn’t support the HID protocol. You’ll need to configure your (which is why the RS232 shield is required).
development board by installing version 4.1.1 of Once Visual C# Express is installed, attach the
the beta firmware, which includes support for RS232-to-USB cable and open Windows Device
HID. You’ll find a zip folder containing the beta Manager to determine which COM port Windows
firmware at bit.ly/1a7f6MB. (You’ll need to create an assigned to that cable.
account by registering with Secret Labs in order When I attached the Parallax RS232-to-USB
to download the file.) converter to my development machine, Windows
The download page on the Web site includes mapped it to COM6, as Figure 4 shows.
instructions for updating the firmware. However, Now that I know the COM port associated
these instructions are fairly complex, particularly with the converter, I can power up my Netduino
if you’re new to the Netduino. The video at bit.ly/ Plus 1, attach the RS232-to-USB cable, and start
1d73P9x is a helpful, concise description of the an instance of Visual C# Express to complete
firmware upgrade process. Figure 3 The Sensor Pin-Outs the download.
msdnmagazine.com March 2014 53
Supporting the USB Transport As I noted earlier, Microsoft
supports HID devices running over USB, Bluetooth, Bluetooth LE
and I2C. However, the sample device described in this article uses
the USB transport. What this actually means is that USB drivers will
be moving packets in both directions: packets originating with the
device are passed up to the HID driver (which passes them on to
the API if there are interested apps); packets originating with the
HID driver are passed back down to the device.
Windows uses specific data issued by the device upon connec-
tion to identify which USB drivers it should load.
an Open method that’s called from within the Main routine of 0x95,0x01, //HID_REPORT_COUNT(1),
the Program class. As you can see in Figure 7, the Open method: 0x81,0x02, //HID_INPUT(Data_Var_Abs),
InstanceId string for each connected device; the string includes the The GetDeviceSelector method returns an Advanced Query
VID and PID for the given device. In the case of the sample tempera- Syntax (AQS) string in the CustomSensorSelector variable. The app
ture sensor, the DeviceInstanceId string has the form: then uses this string when it creates a device watcher and when it
HID\VID_16C0&PID_0012\6&523698d&0&0000 enumerates the DeviceInformation objects.
Figure 10 shows the app as it appears after enumeration has The Second Stage of Device Connection The second stage of
completed and the user has connected to the device. device connection allows the user to make a selection from the list
The First Stage of Device Connection Here are the methods of connected devices. This stage establishes the currently selected
called during the first stage of device connection (before the UI is device. Here are the methods (all in EventHandlerForDevices.cs)
displayed), along with tasks accomplished by each method: called and what each one does.
DeviceConnect (Scenario1_DeviceConnect.xaml.cs) invokes OpenDeviceAsync opens the connection to the device.
the CustomTemperatureSensor.InitializeComponent method, RegisterForAppEvents registers for app suspension and
which initializes the app’s UI components such as the text blocks resume events.
and buttons. RegisterForDeviceAccessStatusChange listens for changes
InitializeDeviceWatchers (Scenario1_DeviceConnect.xaml.cs) in device-access permissions.
invokes the HidDevice.GetDeviceSelector method to retrieve a RegisterForDeviceWatcherEvents registers for the added
device selector string. (The selector is required in order to create and removed events.
a device watcher.) Once the selector is obtained, the app invokes StartDeviceWatcher starts the device watcher.
DeviceInformation.Cre- SelectDeviceInList checks to see if the user has selected a
ateWatcher to create the device and, if so, saves the index for that device. It also writes a
DeviceWatcher object “Currently connected …” string to the output window if the con-
and then EventHandler- nection is successful.
ForDevice.Current.Add-
DeviceWatcher. (This Figure 13 Reading and Displaying Sensor Data
last method allows the
private async void OnInputReportEvent(HidDevice sender,
app to monitor changes HidInputReportReceivedEventArgs eventArgs)
in device status.) {
// Retrieve the sensor data
AddDeviceWatcher HidInputReport inputReport = eventArgs.Report;
(EventHandlerForDe- IBuffer buffer = inputReport.Data;
DataReader dr = DataReader.FromBuffer(buffer);
vices.cs) creates the event byte[] bytes = new byte[inputReport.Data.Length];
handlers for three device dr.ReadBytes(bytes);
In terms of the HID API, the primary code of interest is in the registeredDevice = EventHandlerForDevice.Current.Device;
public async Task<Boolean> OpenDeviceAsync(DeviceInformation deviceInfo, Once the event handler is registered, it reads each input report
String deviceSelector) issued by the sensor and uses the new temperature value to update
{
// This sample uses FileAccessMode.ReadWrite to open the device the TemperatureSlider control. After it updates the control, this
// because you don’t want other apps opening the device and method writes the current temperature and report interval values
// changing the state of the device.
// FileAccessMode.Read can be used instead. to the Output section of the app, as shown in Figure 13.
device = await HidDevice.FromIdAsync(deviceInfo.Id, FileAccessMode.ReadWrite);
comments.Insert(commentToSave);
62 msdn magazine
Untitled-1 1 11/26/12 3:02 PM
constructs a dynamic object out of them, and the resulting object • Format: The general-purpose regular-expression (using
just gets inserted into the comments DynamicRepository. Where the Microsoft .NET Framework Regex class) validation.
do the names of the object’s properties come from? From the HTML • Numericality: Pretty much everything to do with numeric
form that originated all of this. values, including marking a field as “integer-only,” greater-
Wacky, huh? Almost feels like you’re being lazy or something. than and less-than restrictions, or simple even/odd tests.
Anyway, give it a run, and sure enough, now comments are • Conditional: The catch-all “escape hatch” for any
being added in. validation not covered elsewhere—a field must satisfy
a condition described using a lambda function.
Validate Me The last one, Conditional, isn’t actually a validation type in
As written, though, the system has a major flaw (well, according and of itself, but a feature present on most (if not all) of the other
to user requirements, anyway): It’s perfectly permissible for two validation types, and therefore deserves a little more explanation.
blog entries to have the exact same title, and that’s not OK. (Read- Imagine an Order object, for orders in a traditional e-commerce
ers might get confused as to which one to read, the one titled “LOL system. For said systems, a credit card number is only necessary
Kittehs” or the other one titled “LOL Kittehs.”) Thus, you need a if the user wants to use a credit card for payment. Similarly, an
way of enforcing some kind of uniqueness on the code, so users address to which to ship the product is only necessary if the user
can’t accidentally put in duplicate-titled blog entries. purchased anything other than a digital download. These two con-
In a traditional Web framework, this would be a two-part job. tingencies are neatly expressed using two conditional validations,
First, the model object (Blog) would have to define some kind of as shown in Figure 1.
“ask me if I’m valid” method, which I’ll call IsValid for lack of any-
}
}
THANKS to the following technical expert for reviewing this article:
Amir Rajan (Oak project creator)
msdnmagazine.com March 2014 65
MODERN APPS RACHEL APPEL
66 msdn magazine
expertise worth sharing
Washington State Convention Center s April 1-3, 2014
keynote speakers
Scott Ambler Steve Denning
ALM Thought Leader and Co-creator of DAD Framework Award-winning Author
Disciplined Agile Delivery: The Foundation for Scaling Agile Transforming Management through Agile
plenary speakers
Mike Brittain James Whittaker Dave West
Director of Engineering, Etsy Distinguished Technical Evangelist, Microsoft Chief Product Officer, Tasktop
sponsors
diamond platinum
WinJS control.
sample data looks like at run time.
With the reimagining of Windows came the notion of putting
content front and center, and, as you can see, this template does
just that. The XAML Hub project template’s HubPage.xaml file reveals the
The XAML Hub template project works the same conceptually Hub control firmly seats itself in a Grid control that serves as the
as does the HTML template, relying on the hub as the main entry root container for the page and Hub.
point, being navigable to sections and details. Of course, the In the DataModel folder is a file named SampleData.json con-
implementation is different, and you can see this by examining taining sample data. Also in the folder is a SampleDataSource.cs file
the folder structure, which reveals the following directories: that transforms the JSON data into usable classes for C# or Visual
Figure 2 The HTML that Creates the Hub Control
<div class="hub" data-win-control="WinJS.UI.Hub"> "data-win-options="{ onheaderinvoked:
<div class="hero" data-win-control="WinJS.UI.HubSection"></div> select('.pagecontrol').winControl.section3HeaderNavigate }">
<div class="section1" data-win-control="WinJS.UI.HubSection" <div class="itemTemplate" data-win-control="WinJS.Binding.Template">
data-win-options="{ isHeaderStatic: true }" <img src="#" data-win-bind="src: backgroundImage; alt: title" />
data-win-res="{ winControl: {'header': 'Section1'} }"> <div class="win-type-medium" data-win-bind="textContent: title"></div>
<img src="/images/gray.png" width="420" height="280" /> <div class="win-type-small"
<div class="subtext win-type-x-large" data-win-res=" data-win-bind="textContent: description"></div>
{ textContent: 'Section1Subtext' }"></div> </div>
<div class="win-type-medium" <div class="itemslist win-selectionstylefilled" data-win-control=
data-win-res="{ textContent: 'DescriptionText' }"></div> "WinJS.UI.ListView" data-win-options=
<div class="win-type-small"> "{layout: {type: WinJS.UI.GridLayout},
<span data-win-res="{ textContent: 'Section1Description' }"></span> selectionMode: 'none',
<span data-win-res="{ textContent: 'Section1Description' }"></span> itemTemplate: select('.section3 .itemTemplate'), itemDataSource:
<span data-win-res="{ textContent: 'Section1Description' }"></span> select('.pagecontrol').winControl.section3DataSource, oniteminvoked:
</div> select('.pagecontrol').winControl.section3ItemNavigate
</div> }">
<div class="section2" data-win-control="WinJS.UI.HubSection" </div>
data-win-options="{ isHeaderStatic: true }" </div>
data-win-res="{ winControl: {'header': 'Section2'} }"> <div class="section4" data-win-control="WinJS.UI.HubSection"
<div class="item-title win-type-medium" data-win-options="{ isHeaderStatic: true }"
data-win-res="{ textContent: 'Section2ItemTitle' }"></div> data-win-res="{ winControl: {'header': 'Section4'} }">
<div class="article-header win-type-x-large" <div class="top-image-row">
data-win-res="{ textContent: 'Section2Subtext' }"></div> <img src="/images/gray.png" />
<div class="win-type-xx-small" </div>
data-win-res="{ textContent: 'Section2ItemSubTitle' }"></div> <div class="sub-image-row">
<div class="win-type-small"> <img src="/images/gray.png" />
<span data-win-res="{ textContent: 'Section2Description' }"></span> <img src="/images/gray.png" />
<span data-win-res="{ textContent: 'Section2Description' }"></span> <img src="/images/gray.png" />
<span data-win-res="{ textContent: 'Section2Description' }"></span> </div>
<span data-win-res="{ textContent: 'Section2Description' }"></span> <div class="win-type-medium"
<span data-win-res="{ textContent: 'Section2Description' }"></span> data-win-res="{ textContent: 'DescriptionText' }"></div>
<span data-win-res="{ textContent: 'Section2Description' }"></span> <div class="win-type-small">
</div> <span data-win-res="{ textContent: 'Section4Description' }"></span>
</div> <span data-win-res="{ textContent: 'Section4Description' }"></span>
</div>
<div class="section3" data-win-control="WinJS.UI.HubSection" </div>
data-win-res="{ winControl: {'header': 'Section3'} } </div>
controls, which define sections or groups of data. HubSections can As you can see, XAML syntax is a bit more verbose than HTML.
contain any valid HTML tags, such as <div> or <img>, or a WinJS That’s because you code layout and styles right in the XAML page
control, such as the ListView control. By default, the hub.html file’s (though XAML styles can be placed in a resource dictionary), while
Hub control encloses five sections, one named hero and four more in HTML the layout and style rules are CSS (more on styling later).
designated by their class attributes (such as section1, section2 and
so on). In the HubSections, the <div> and <img> tags are the most Data Binding and the Hub Control
common child elements, but any valid HTML or WinJS controls Arrays or JSON (which usually serializes to an array anyway) are
will work to display data in a different layout. Changing the layout the customary ways to work with data in WinJS, as well as in many
is a great way to personalize your app, but don’t forget to adhere other Web or client languages. This is no different with the Hub
to the Windows UX guidelines at bit.ly/1gBDHaW. Figure 2 shows a project. You can replace the data in \js\data.js with custom data
complete sample of the necessary HTML (you’ll see its CSS later) broken into however many groups you plan to use. You’ll find two
to create a Hub control with five sections. Inspecting the code in arrays as sample data in the data.js file, one for grouping and one
Figure 2 shows section 3 is the navigable section, while the rest for individual items that tie into a specific group. If you’re familiar
are not navigable. with some of the other WinJS project templates, then you’ll notice
In XAML, the Hub control uses a <Hub> element that contains this is the same sample data.
<Hub.Header> and <HubSection> elements. In turn, the child head- In the \pages\hub\hub.js file are the calls to the members of the
ings and sections contain Grid and other XAML controls, such as the Data namespace that obtain group and item data:
StackPanel, as well as text blocks. Figure 3 shows the XAML required var section3Group = Data.resolveGroupReference("group4");
var section3Items = Data.getItemsFromGroup(section3Group);
to create the Hub control used in the Visual Studio templates.
70 msdn magazine Modern Apps
The section3Group and section3Items are global objects. of the Hub control. The hero fills roughly half of the left side of
Figure 2 shows the data-binding syntax for the ListView control. In the viewable part of screen with a light gray background and, of
hub.js, after the ready function, the code sets section3DataSource, course, it’s a great way to put a special piece of content where no
a property of the Hub control: user can miss it! You can fill it with lots of data, and graphic data or
section3DataSource: section3Items.dataSource, multimedia works quite nicely to show off here.
The Hub control uses the preceding code to data bind to the As you can see, the CSS in Figure 4 shapes and styles the Hub
ListView (Figure 2 shows the data-bound ListView code). control, and most of it deals with the layout and sizing of the
HubSections. Elements and WinJS controls inside the HubSections
In Windows Store apps built with apply the styles from ui-light.css or ui-dark.css, until you overwrite
them with your own styles.
JavaScript, you can style the Hub HTML apps rely on CSS for styling. XAML apps rely on XAML
for styling. This means that XAML has several attributes you
control with CSS. apply to tags to enforce styling definitions called resources. For
example, the code that styles a TextBlock is the Style attribute and
it references a built-in (static resource dictionary) style named
In XAML apps using C#, you have the same basic occurrences, SubheaderTextBlockStyle:
as code from the HubPage.xaml.cs file indicates the following <TextBlock Style="{StaticResource SubheaderTextBlockStyle} />
declaration for a view model of type ObservableDictionary, along The layout of a page is also XAML, as all the Hubs, Grids and other
with its corresponding property declaration (this is where you can elements contain inline coordinates for their on-screen position as
return your own data): well as size. You can see throughout Figure 3 there are margins, posi-
private ObservableDictionary defaultViewModel = new ObservableDictionary(); tioning, and row and column settings that position elements, all inline
public ObservableDictionary DefaultViewModel
{ in the XAML. HTML is originally a Web technology, and conserving
get { return this.defaultViewModel; } bandwidth by using CSS instead of HTML is a real benefit. Here in
}
the land of XAML, it’s all client-side, so UI caching isn’t so much of
Later in the file, code sets a page-level view model by calling
an issue and styles can go inline. A nice upside of XAML is that you
GetGroupAsync, which, as its name implies, runs asynchronously:
need to do very little to ensure a responsive design. Just be sure to set
var sampleDataGroup = await SampleDataSource.GetGroupAsync("Group-4");
two <RowDefinition> elements to a height of “Auto” and “*”:
Although the call obtains Group-4 data, you assign it to a view
<Grid.RowDefinitions>
model named Section3Items to assign it to those items. Consider <RowDefinition Height="Auto"/>
the hero section as Section 0, meaning the Section 3 items will align <RowDefinition Height="*"/>
</Grid.RowDefinitions>
with the Group-4 data:
The rows will automatically respond to app view state changes,
this.DefaultViewModel["Section3Items"] = sampleDataGroup;
making the layout fluid while saving extra code. Figure 3 shows a
This is all you need in the codebehind. In XAML, notice the
few references to auto-height row definitions.
DataContext attribute binds to Section3Items.The other attributes
aren’t necessary for data binding, but act as an aid for the design
tools in Visual Studio or Blend, as designated by the “d” namespace:
Samples Available
<HubSection IsHeaderInteractive="True" DataContext="{Binding Section3Items}"
Once you’ve modified the Hub control, performed data retrieval
d:DataContext="{Binding Groups[3], Source={d:DesignData and binding, and set styles, you’re good to go. Don’t forget to add
Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}"
x:Uid="Section3Header" Header="Section 3" Padding="40,40,40,32">
modern touches such as tiles, search and other Windows integra-
While working with local sample data, you have many options tion to your app. The Hub project template is an easy way to build
for data access, including File IO, SQLite, Web Storage, IndexedDB, and publish apps quickly, whether in HTML or XAML. Using the
REST services and Windows Azure, to name a few. If you want to hub navigational pattern with the Hub control enables you to build
review what data options are available, see my March 2013 arti- an effective and rich UX that adheres to modern UI principles.
cle, “Data Access and Storage Options in Windows Store Apps,” You can download Hub control samples covering many aspects of
at msdn.microsoft.com/magazine/jj991982. Windows app development at the following locations:
• HTML sample: bit.ly/1m0sWTE
Styling the Hub Control • XAML sample: bit.ly/1eGsVAH Q
In Windows Store apps built with JavaScript, you can style the Hub
control with CSS. The \hub\hub.css file contains all the default RACHEL APPEL is a consultant, author, mentor and former Microsoft employee with
CSS related to the Hub control. Feel free to add your own styles to more than 20 years of experience in the IT industry. She speaks at top industry
conferences such as Visual Studio Live!, DevConnections, MIX and more. Her
change the size of the elements or their layout. Figure 4 shows the
expertise lies within developing solutions that align business and technology
complete CSS in hub.css. Notice there’s a .hubpage class selector that focusing on the Microsoft dev stack and open Web. For more about Appel, visit
uses HTML5 semantic role attributes such as header[role=banner] her Web site at rachelappel.com.
and section[role=main] to designate the general styles for the hub.
After that, the CSS in Figure 4 shows the “.hubpage .hub .hero” THANKS to the following technical expert for reviewing this article:
descendant selector, which creates the featured (hero) section Frank La Vigne (Microsoft)
£Web Dev Live! – NEW EVENT! Web Dev Live! will dive deep to
explore all that is HTML5, JavaScript and ASP.NET.
£Modern Apps Live! – Launch your mobile, cross-device & cloud development
training here.
£SharePoint Live! – Set your course for collaboration with these sessions
designed strictly for devs.
£SQL Server Live! – Your Mission? Conquering coding against SQL Server.
This means you have Àve events with over a hundred sessions to choose from –
mix and match sessions to create your own, custom event line-up - it’s like no
other dev conference available today.
magazine
The triangle is the most basic two-dimensional figure. It’s nothing In contrast, triangles aren’t found at all in most 2D graphics pro-
more than three points connected by three lines, and if you try to gramming interfaces, where the most common two-dimensional
make it any simpler, it collapses into a single dimension. On the primitives are lines, curves, rectangles and ellipses. So it’s somewhat
other hand, any other type of polygon can be decomposed into a surprising to find triangles pop up in a rather obscure corner of
collection of triangles. Direct2D. Or maybe it’s really not that surprising: Because Direct2D
Even in three dimensions, a triangle is always flat. Indeed, one is built on top of Direct3D, it seems reasonable for Direct2D to
way to define a plane in 3D space is with three non-collinear points, take advantage of the triangle support in Direct3D and the GPU.
and that’s a triangle. A square in 3D space isn’t guaranteed to be The triangle structure defined in Direct2D is simple:
flat because the fourth point might not be in the same plane as struct D2D1_TRIANGLE
{
the other three. But that square can be divided into two triangles, D2D1_POINT_2F point1;
each of which is flat, although not necessarily on the same plane. D2D1_POINT_2F point2;
D2D1_POINT_2F point3;
};
Triangles in Direct2D
HRESULT InterrogableTessellationSink::Close()
{
// Assume the class accessing the tessellation sink knows what it's doing
Triangles are ubiquitous in 3D computer graphics. Much of the return S_OK;
work performed by a modern graphics processing unit (GPU) }
involves rendering triangles, so of course Direct3D programming // Method for this implementation
involves working with triangles to define solid figures. std::vector<D2D1_TRIANGLE> InterrogableTessellationSink::GetTriangles()
{
return m_triangles;
Code download available at msdn.microsoft.com/magazine/msdnmag0314. }
74 msdn magazine
profound difference between ID2D1Geometry and ID2D1Mesh
objects that’s revealed by how you create these two objects.
Geometries are mostly just collections of coordinate points, so
geometries are device-independent objects. You can create various
types of geometries by calling methods defined by ID2D1Factory.
A mesh is a collection of triangles, which are just triplets of
coordinate points, so a mesh should be a device-independent
object as well. But you create an ID2D1Mesh object by calling a
method defined by ID2D1RenderTarget. This means the mesh is
a device-dependent object, like a brush.
This tells you the triangles that comprise the mesh are stored
in a device-dependent manner, most likely in a form suitable for
Figure 2 A Rounded Rectangle Decomposed into Triangles processing by the GPU, or actually on the GPU. And this means
that FillMesh should execute much faster than FillGeometry for
Direct2D and Direct3D programming. In Direct2D, tessellation is the equivalent figure.
the process of decomposing a two-dimensional area into triangles. Shall we test that hypothesis?
The ID2D1TessellationSink interface has just two methods: Add- Among the downloadable code for this article is a program
Triangles (which adds a collection of D2D1_TRIANGLE objects to named MeshTest that creates a path geometry for a 201-point star,
the collection) and Close, which makes the mesh object immutable. and slowly rotates it while calculating and displaying the frame rate.
Although your program can call AddTriangles itself, often it will When the program is compiled in Debug mode for the x86 and
pass the ID2D1TessellationSink object to the Tessellate method runs on my Surface Pro, I get a frame rate of less than 30 frames
defined by the ID2D1Geometry interface: per second (FPS) when rendering the path geometry (even if the
geometry->Tessellate(IdentityMatrix(), tessellationSink); geometry is outlined to eliminate overlapping areas and flattened
tessellationSink->Close();
to eliminate curves), but the frame rate leaps up to 60FPS when
The Tessellate method generates triangles that cover the areas
rendering the mesh.
enclosed by the geometry. After you call the Close method, the sink
can be discarded and you’re left with an ID2D1Mesh object. The
process of generating the contents of an ID2D1Mesh object using
an ID2D1TessellationSink is similar to defining an ID2D1Path-
Geometries are mostly
Geometry using an ID2D1GeometrySink. just collections of coordinate
You can then render this ID2D1Mesh object using the FillMesh
method of ID2D1RenderTarget. A brush governs how the mesh points, so geometries are
is colored:
deviceContext->FillMesh(mesh, brush);
Keep in mind that these mesh triangles define an area and not
device-independent objects.
an outline of an area. There is no DrawMesh method.
Conclusion: For complex geometries, it makes sense to convert
FillMesh has a limitation: Anti-aliasing can’t be enabled when
them to meshes for rendering. If the need to disable anti-aliasing
FillMesh is called. Precede FillMesh with a call to SetAntialiasMode:
deviceContext->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
to render this mesh is a deal-breaker, you might want to check out
You might wonder: What’s the point? Why not just call ID2D1GeometryRealization, introduced in Windows 8.1. This
FillGeometry on the original geometry object? The visuals should combines the performance of ID2D1Mesh but allows anti-aliasing.
be the same (aside from the anti-aliasing). But there’s actually a Keep in mind meshes and geometry realizations must be recreated if
the display device is recreated, just as with other device-dependent
resources such as brushes.
Figure 6 A Still from the OutThereAndBackAgain Program Figure 7 The TextMorphing Display
78 msdn magazine DirectX Factor
For OutThereAndBackAgain, I envisioned text that would fly contains a single-triangle ID2D1Mesh object, as well as informa-
apart into its composite triangles, which would then come back to tion necessary to take that triangle on a journey outward and back
form the text again. Figure 6 shows this process at 3 percent into again. This journey takes advantage of a feature of geometries you
the flying-apart animation. can use independently of rendering. The ComputeLength method
The CreateWindowSizeDependentResources method in the in ID2D1Geometry returns the total length of a geometry, while
OutThereAndBackAgainRenderer class assembles information ComputePointAtLength returns a point on the curve and a tangent
about each triangle in a structure I call TriangleInfo. This structure to the curve at any length. From that information you can derive
translate and rotate matrices.
Figure 8 Update and Render in TextMorphing As you can see in Figure 6, I used a gradient brush for the text
void TextMorphingRenderer::Update(DX::StepTimer const& timer)
so that triangles of slightly different colors would cross paths
{ and intermingle a bit. Even though I’m using only one brush, the
...
desired effect requires the Render method to call SetTransform and
// Calculate an interpolation factor FillMesh for every single-triangle mesh. The gradient brush is applied
float t = (float)fmod(timer.GetTotalSeconds(), 10) / 10;
t = std::cos(t * 2 * 3.14159f); // 1 to 0 to -1 to 0 to 1
as if the mesh were in its original position prior to the transform.
t = (1 - t) / 2; // 0 to 1 to 0 I wondered if it would be efficient for the Update method to
// Two functions for interpolation
transform all the individual triangles “manually” with calls to the
std::function<D2D1_POINT_2F(D2D1_POINT_2F, D2D1_POINT_2F, float)> TransformPoint method of the Matrix3x2F class, and to consol-
InterpolatePoint =
[](D2D1_POINT_2F pt0, D2D1_POINT_2F pt1, float t)
idate these in a single ID2D1Mesh object, which would then be
{ rendered with a single FillMesh call. I added an option for that, and
return Point2F((1 - t) * pt0.x + t * pt1.x,
(1 - t) * pt0.y + t * pt1.y);
sure enough, it was faster. I woudn’t have imagined that creating
}; an ID2D1Mesh in each Update call would work well, but it does.
std::function<D2D1_TRIANGLE(D2D1_TRIANGLE, D2D1_TRIANGLE, float)>
The visuals are slightly different, however: The gradient brush is
InterpolateTriangle = applied to the transformed triangles in the mesh, so there’s no
[InterpolatePoint](D2D1_TRIANGLE tri0, D2D1_TRIANGLE tri1, float t)
{
intermingling of colors.
D2D1_TRIANGLE triangle;
triangle.point1 = InterpolatePoint(tri0.point1, tri1.point1, t);
triangle.point2 = InterpolatePoint(tri0.point2, tri1.point2, t);
Text Morphing?
triangle.point3 = InterpolatePoint(tri0.point3, tri1.point3, t); Suppose you tessellate the glyph outline geometries of two text
return triangle;
};
strings—for example, the words “DirectX” and “Factor” that make
up the name of this column—and pair up the triangles for inter-
// Interpolate the triangles
int count = m_triangleInfos.size();
polation. An animation could then be defined that transforms one
std::vector<D2D1_TRIANGLE> triangles(count); word into the other. It’s not exactly a morphing effect, but I don’t
for (int index = 0; index < count; index++)
know what else to call it.
{ Figure 7 shows the effect midway between the two words, and
triangles.at(index) =
InterpolateTriangle(m_triangleInfos.at(index).triangle[0],
with a little imagination you can almost make out either “DirectX”
m_triangleInfos.at(index).triangle[1], t); or “Factor” in the image.
}
Optimally, each pair of morphing triangles should be spatially
// Create a mesh with the interpolated triangles close, but minimizing the distances between all the pairs of trian-
m_deviceResources->GetD2DDeviceContext()->CreateMesh(&m_textMesh);
ComPtr<ID2D1TessellationSink> tessellationSink;
gles is akin to the Traveling Salesman Problem. I took a relatively
m_textMesh->Open(&tessellationSink); simpler approach by sorting the two collections of triangles by
tessellationSink->AddTriangles(triangles.data(), triangles.size());
tessellationSink->Close();
the X coordinates of the triangle center, and then separating the
} collections into groups representing ranges of X coordinates, and
// Renders a frame to the screen
sorting those by the Y coordinates. Of course, the two triangle col-
void TextMorphingRenderer::Render() lections are different sizes, so some triangles in the word “Factor”
{
...
correspond to two triangles in the word “DirectX.”
Figure 8 shows the interpolation logic in Update and the
if (m_textMesh != nullptr)
{
rendering logic in Render.
Matrix3x2F centerMatrix = D2D1::Matrix3x2F::Translation( With that, I think I’ve satisfied my curiosity about 2D triangles
(logicalSize.Width - (m_geometryBounds.right + m_geometryBounds.left)) / 2,
(logicalSize.Height - (m_geometryBounds.bottom + m_geometryBounds.top)) / 2);
and I’m ready to give those triangles a third dimension. Q
context->SetTransform(centerMatrix *
m_deviceResources->GetOrientationTransform2D());
context->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); CHARLES PETZOLD is a longtime contributor to MSDN Magazine and the author
context->FillMesh(m_textMesh.Get(), m_blueBrush.Get()); of “Programming Windows, 6th edition” (Microsoft Press, 2012), a book about
} writing applications for Windows 8. His Web site is charlespetzold.com.
...
}
THANKS to the following Microsoft technical experts for reviewing this article:
Jim Galasyn and Mike Riches
msdnmagazine.com March 2014 79
DON’T GET ME STARTED DAVID S. PLATT
Illustration: Reprinted with permission of John Hart Studios Inc.
I’ve always enjoyed the comic strip, “Wizard You’d think that enterprise developers by
of Id,” which is set in medieval times. Its now would’ve realized the importance of
creators died in 2008, but their descendants usability, as they directly benefit from greater
have kept the strip current for today’s Inter- user productivity, fewer catastrophic errors,
net age (see bit.ly/1d7eIYK). Peasants (known, of and lower training and support costs. But the
course, as Idiots) rampage through the town strongest bastions of bad usability are places
waving signs that read, “The king is a fink!” where users are locked in and can’t choose.
Figure 1 shows the king’s response. Cormac Herley of Microsoft Research,
That same scenario is now exploding in the investigating the burden security policies
field of enterprise software. Last December, place on users, found them highest not where
Avon (the makeup guys) pulled the plug on a data was most sensitive, but rather in captive
new version of their order management soft- situations, especially governments and uni-
ware based on SAP. The Wall Street Journal in versities, where the enterprise didn’t suffer
December reported the company’s sales force the market consequences of its bad usability
of independent reps “found the new system (see bit.ly/1eK6Dhu). Avon is the tipping point
so burdensome and disruptive to their daily where this phenomenon starts to change.
routine that many left Avon.” Whether you’re dealing with the enter-
A spokesman for SAP was later quoted prise or consumer sector, UX design has
saying that Avon’s order management system Figure 1 Avon’s management was slow to happen before anything else can. To
“is working as designed, despite any issues to recognize unrest in the ranks. meet today’s standard of care, you can’t wait
with the implementation of this project.” until your program works and then throw it
Really? That means unless Avon’s goal was to reduce its workforce over the fence for the decorators to pretty up. The decorators can
through bad software instead of layoffs, the company implemented round off the corners of the File Open/Save dialog box and give it
a terrible design. And that weasel spokesman (but, like Mark Twain, nice color gradients. But the UX interaction designer determines
I repeat myself) should read my column about the word “issue.” whether to make the user save documents manually (a la Word),
(See msdn.microsoft.com/magazine/ff955613.) or implement automatic saving (a la OneNote). That choice very
As smoking in public was once common, it was once common much dictates the code to write. So UX design has to come first.
to force users to contort themselves into five-dimensional hyper- And with Avon, clearly, it didn’t.
pretzels to match their software—to become “computer literate,” That needs to change. As Steve Rosenbush wrote in his CIO
in the term of that day. UX guru Alan Cooper wrote that a com- Journal blog on wsj.com: “People who are accustomed to using
puter literate user is one who “has been hurt so often that the scar simple, well-designed applications in their personal lives have no
tissue is so thick that he no longer feels the pain.” Users accepted patience for disappointing technology at work.” Amen.
this as the price of getting their computing jobs done. That attitude And so, my friends, when you work on your enterprise apps,
doesn’t cut it anymore. you had better start paying attention to usability. Because the
Success in consumer-sector software and hardware has been enterprise-sector peasants are indeed revolting. And there’s no
driven by usability for seven years now, since the first Apple iPhone. stopping them. If your boss won’t let you put UX first, ask him how
But it’s taken much longer for that requirement to cross over into he feels about wearing tar and feathers. Q
the enterprise sector. The whole bring-your-own-device move-
ment arose from early adopter iPhone and iPad users wanting DAVID S. PLATT teaches programming .NET at Harvard University Extension School
their enterprise software to work as easily as their consumer apps. and at companies all over the world. He’s the author of 11 programming books, including
“Why Software Sucks” (Addison-Wesley Professional, 2006) and “Introducing
And now, like the Wizard’s newspaper pagemate Popeye the Sailor, Microsoft .NET” (Microsoft Press, 2002). Microsoft named him a Software Legend
enterprise users have stood up and roared, “That’s all I can stands! in 2002. He wonders whether he should tape down two of his daughter’s fingers so
I can’t stands no more!” (See bit.ly/1a7BiWZ.) she learns how to count in octal. You can contact him at rollthunder.com.
80 msdn magazine
Untitled-2 1 5/31/13 10:57 AM
Untitled-5 1 2/4/14 1:21 PM
Power
fulFi
leAPI
sthatar
eeasyandi
ntui
ti
vet
ouse
Nat
iveAPI
sfor
.
NET,
Java,
Andr
oid&Cl
oud
AsposeAPIshelpdevel opers
wit
hallf
iler
elat
edt asks,fr
om
conver
sionstoreporti
ng.
DOC,XLS,
JPG,PNG, PDF
BMP,
MSG, PPT,VSD,XPS
&manyotherf
ormats.
Al
soPower
ing
www.
aspose.
com
US Sal
es:+18882776734 EU Sales:+441414161112 AU Sal
es:+61280035926
sal
es@aspose.
com sal
es.europe@aspose.
com sales.
asi
apaci
fi
c@aspose.
com
CONVERT
PRINT
CREATE
COMBINE
MODIFY
100%S
tandal
one-NoOf
fi
ceAut
omat
ion
ASPOSE.
TOT
AL
As
pos
e.Tot
alf
or.
NET As
pos
e.Tot
alf
orCl
oud
As
pos
e.Tot
alf
orJ
ava As
pos
e.Tot
alf
orAndr
oid
.
NET J
ava oud Andr
Cl oid
pa
ge4
As
pos
e.Cel
l
s
Aspose.Cell
sletsyoucr
eate,impor
t,andexpor
tspreadsheet
s
andalsoal l
owsyout omanipul
atecont
ent
s,cel
lfor
mat ti
ng,
andfil
epr otect
ion.
Aspose.
Cell
scomeswit
hcompletesuppor
tforchar
tingand
support
sallst
andar
dchar
ttypes.Al
so,youcanconvertchar
ts
toimages.
Easi
lyconver
twor
ksheet
stoi
magesaswel
lasaddi
ngi
mages
toworksheet
satr
unti
me.
GetyourFREETr ialat
US Sal
es:+18882776734
FAX:+18668109465 htt
p://
www. aspose.com
sal
es@aspose.
com
EU Sales:+441414161112
sal
es.europe@aspose.
com
NoOf
ficeAut
omat
ion
Aspose.Cell
sdoesnotr
equir
eMicrosof
tOff
icet
o
beinstall
edonthemachineinor
dert owor
k.
pa
ge6
pa
ge7
pa
ge10
pa
ge11
pa
ge13
pa
ge14
Wantt
owor
kwi
thr
ealbusi
nessdocument
s?
Nowy
ouc
an!
Gety
ourFREETRI
ALatwww.
aspos
e.c
om
pa
ge18
pa
ge19
As
pos
ehas4Suppor
tSer
vicest
obes
tsui
tyourneeds
Fr
eeSuppor
t Suppor
tFor
umswi
thnoChar
ge T
echni
calSuppor
tisanissue
thatAsposetakesveryseriousl
y.
24hourresponsetimeint
he
Pr
ior
itySuppor
t week,i
s s
uees cal
ati
on, Soft
war emustwor kquicklyand
dedi
catedforum
dependably.Whenpr oblemsar i
s e,
Ent
erpr
is t C
eSuppor ommuni
manager
s
cat
,i
ewi
nfl
thpr
oduct
uencetheroadmap
developer
sneedans wersi nahur ry
.
Weens urethatourcli
ent srecei
ve
Spons
oredSuppor
t Getthefeatureyouneedbui
ltnow usefulans
wer sandsoluti
onsqui ckl
y.
Emai
l•Li
veChat•For
ums
CONTACTUS
US Sal
es:+18882776734
sal
es@aspose.
com
EU Sales:+441414161112
sal
es.europe@aspose.
com
AU Sales:+61280035926
sal
es.asiapaci
fi
c@aspose.
com