®
Microsoft Silverlight Graphics
tm
Oswald Campesato Course Technology PTR A part of Cengage Learning
Australia
.
Brazil
.
Japan
.
Korea
.
Mexico
.
Singapore
.
Spain
.
United Kingdom
.
United States
Microsoft SilverlightTM Graphics Oswald Campesato R
Publisher and General Manager, Course Technology PTR: Stacy L. Hiquet Associate Director of Marketing: Sarah Panella Manager of Editorial Services: Heather Talbot
2008 Course Technology, a part of Cengage Learning. C
ALL RIGHTS RESERVED. No part of this work covered by the copyright herein may be reproduced, transmitted, stored, or used in any form or by any means graphic, electronic, or mechanical, including but not limited to photocopying, recording, scanning, digitizing, taping, Web distribution, information networks, or information storage and retrieval systems, except as permitted under Section 107 or 108 of the 1976 United States Copyright Act, without the prior written permission of the publisher.
Marketing Manager: Mark Hughes Acquisitions Editor: Mitzi Koontz Project Editor: Karen A. Gill Technical Reviewer: Lisa Bucki PTR Editorial Services Coordinator: Erin Johnson Copy Editor: Gene Redding Interior Layout Tech: ICC Macmillan Inc. Cover Designer: Tyler Creative Services Indexer: Katherine Stimson Proofreader: Kate Shoup
For product information and technology assistance, contact us at Cengage Learning Customer & Sales Support, 1-800-354-9706. For permission to use material from this text or product, submit all requests online at cengage.com/permissions. Further permissions questions can be e-mailed to
[email protected].
Microsoft and Silverlight are either registered trademarks or trademarks of Microsoft Corporation in the United States or other countries. Java is a trademark of Sun Microsystems, Inc. in the United States and other countries. Python is a trademark of the Python Software Foundation. All other trademarks are the property of their respective owners. Library of Congress Control Number: 2008902384 ISBN-13: 978-1-59863-537-9 ISBN-10: 1-59863-537-9 eISBN-10: 1-59863-698-7 Course Technology 25 Thomson Place Boston, MA 02210 USA Cengage Learning is a leading provider of customized learning solutions with office locations around the globe, including Singapore, the United Kingdom, Australia, Mexico, Brazil, and Japan. Locate your local office at international.cengage.com/region. Cengage Learning products are represented in Canada by Nelson Education, Ltd. For your lifelong learning solutions, visit courseptr.com. Visit our corporate Web site at cengage.com.
Printed in Canada 1 2 3 4 5 6 7 11 10 09 08
This is my third published book, and I would like to dedicate it to my parents. May this book bring joy and happiness into their lives.
Acknowledgments
This book was a pleasure for me, partly because of my passion for graphics. Many people have influenced me: Joe Bianco was an early mentor whose influence is still with me; Alex Pakalniskis taught me about Chicago; Ivan Handler opened my eyes in innumerable ways; and Judy Somos taught me about patience. More recently, I had the pleasure of meeting an eclectic cast of people: Charlie (‘‘Mr. XP’’) Poole, whose worldly travels make him an interesting conversationalist; Rajiv Lakhanpal, who is an Italian at heart; Eli (‘‘canaglia’’) Sigal, with his roguish zest for life; Benedicte and Darach (‘‘be curious and fearless’’) Ennis, both of whom make me wistful for living in Europe again; Brendan Spence and Carol and family, for hosting the wonderful barbecues; Shivdutt Jha, who really enjoyed my imitation of Bob Dylan singing in Hindi; Pierce Hickey, who liked my monstrous Perl-based scanner; Eric Newcomer, with his quiet conviction; Steven Wu, who always cuts to the core of the hoopla; Don Lin, with his shrewd perception; Jamie Osborne, for hosting some outrageous parties; and Andy Winders, who is much better than I will ever be at playing basketball. I hope that Tiziana Balestra (e anche il suo marito Giuseppe) is happy as a mother; with her infectious enthusiasm, she is undoubtedly the favorite Italian instructor of her students. A special thanks to Laurie Dresser (‘‘no real time, no backlog’’), who helped me relocate to San Francisco; Carrie (‘‘Rie’’) Kang, who has influenced me in ways that she does not even realize (and maybe I’ll meet her parents on their next trip); Maxie (he’s a teacup poodle), for his irresistible charm and his contribution to Chapter 11; Hideki Hiura, who shares my mordant humor and reflective nature and always encourages me to become fluent in Japanese (and perhaps some day I’ll attain that level).
Acknowledgments
This book could not have been completed without the help of a lot of other people. I would be remiss if I did not thank Mitzi Koontz (acquisitions editor), Lisa Bucki (technical editor), Karen Gill (project editor), Gene Redding (copyeditor), Kate Shoup (proofreader), Katherine Stimson (indexer), ICC Macmillan, Inc. (the layout team), and Mark Hughes (marketing manager), who made valuable suggestions for improving this book. Finally, I’d like to thank Sherry Stinson, who designed the cover of this book and my SVG book. That’s why they look so good!
v
About the Author
Oswald Campesato is a senior development manager at JustSystems, Inc., where he is involved in business development, R/D for future product development, developing prototypes (Java/XML/XSLT), and attending conferences in the United States, Europe, and Japan. He is the author of Java Graphics Programming Library: Concepts to Source Code and Fundamentals of SVG Programming: Concepts to Source Code.
Contents
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 1
Introduction to Silverlight . . . . . . . . . . . . . . . . . . . . . . . . 1 What Is Silverlight? . . . . . . . . . . . . . . . . . . . . . Silverlight/XAML Naming Convention . . . . . . . Silverlight versus SVG . . . . . . . . . . . . . . . . . . . Downloading and Installing Silverlight. . . . . . . Structure of a Silverlight Application . . . . . . . . A Minimal XAML Document . . . . . . . . . . . . . . A Silverlight/XAML Rectangle . . . . . . . . . . . . . The Silverlight/XAML Coordinate System . . . . . Rendering Polygons with Polygon Objects . . . . Rendering Rectangles with Path Objects . . . . . Rendering Rectangles with Line Objects. . . . . . Rendering Rectangles with a Shadow Effect . . Rendering Rectangles with RectangleGeometry Rendering Triangular Wedges with Shading . . Nested Canvas Objects. . . . . . . . . . . . . . . . . . . Key Constructs . . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 2
xiii
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . .
2 3 3 4 5 6 7 11 12 13 14 16 18 19 20 22 23
Colors, Linear Gradients, and Radial Gradients . . . . . . . . 25 Colors and Their Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 Standard Color Names. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
vii
viii
Contents Rendering a Checkerboard Grid. . . . . . . . . . . . . Rendering Rectangles with Opacity . . . . . . . . . . Rendering a Cube in Silverlight/XAML . . . . . . . . Silverlight/XAML Color Gradients . . . . . . . . . . . . Silverlight/XAML Linear Gradients . . . . . . . . . . . Rendering Rectangles with Linear Gradients . . . Radial Color Gradients . . . . . . . . . . . . . . . . . . . Rendering Parallelograms with Linear Gradients SpreadMethod, RadiusX, and RadiusY . . . . . . . . Key Constructs . . . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 3
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
28 30 33 35 35 35 38 39 41 44 44
Ellipses, Arcs, and Simple 3D Effects . . . . . . . . . . . . . . . . 45 The Silverlight/XAML Ellipse Object . . . . . . . Rendering Ellipses with Linear Gradients . . . Rendering Ellipses with Radial Gradients . . . Creating Elliptic Arcs with Path . . . . . . . . . . Elliptic Arcs with ArcSegment Objects . . . . . Arc-Based Petal Patterns . . . . . . . . . . . . . . . Arc-Based Diamond Patterns . . . . . . . . . . . . Creating 3D Effects with Circles . . . . . . . . . . Rendering Cones with Gradient Shading . . . Rendering Cylinders with Gradient Shading . Key Constructs . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 4
. . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
46 48 50 52 54 57 59 61 63 65 68 68
Be´zier Curves and Color Gradients . . . . . . . . . . . . . . . . . 69 What Are Be´zier Curves? . . . . . . . . . . . . . . . . . . Rendering a Quadratic Be´zier Curve . . . . . . . . . Rendering Cubic Be´zier Curves . . . . . . . . . . . . . Cubic Be´zier Curves and Linear Gradients. . . . . . Double Cubic Be´zier Curves . . . . . . . . . . . . . . . . Double Reflected Cubic Be´zier Curves . . . . . . . . Cubic Quadratic Be´zier Curves . . . . . . . . . . . . . . Be´zier Curves: SpreadMethod, RadiusX, RadiusY Rendering Be´zier Curves with Clip Objects . . . . . Be´zier Curves and BezierSegment Objects . . . . . Using the GeometryGroup Object . . . . . . . . . . . Key Constructs . . . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
70 70 72 73 76 79 81 84 85 87 90 93 94
Contents
Chapter 5
Silverlight/XAML Transformations . . . . . . . . . . . . . . . . . 95 TranslateTransform Transformation . . . . . . . . . RotateTransform Transformation . . . . . . . . . . . ScaleTransform Transformation . . . . . . . . . . . . Multiscaled Cubic Be´zier Curves. . . . . . . . . . . . SkewTransform Transformation . . . . . . . . . . . . MatrixTransform Transformation . . . . . . . . . . . Cylinders and ScaleTransform Transformation . Hourglass: ScaleTransform and SkewTransform Transformations of Text Strings . . . . . . . . . . . . Key Constructs . . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 6
. . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. 96 . 98 101 103 107 109 112 117 123 126 127
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
129 132 135 138 141 145 148 151 152
Mouse Events and Keystroke Events. . . . . . . . . . . . . . . 153 Detecting Mouse Events . . . . . . . . . . . . . . . . Detecting Mouse Click Events . . . . . . . . . . . . Generating Rectangles via Mouse Click Events Freestyle Sketching and Mouse Move Events . Dynamically Adding and Removing Objects . . Mouse Events and Multiple Dynamic Objects . A Basic Board Game . . . . . . . . . . . . . . . . . . . Detecting Keystroke Events . . . . . . . . . . . . . . Processing Keystrokes . . . . . . . . . . . . . . . . . . Key Constructs . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 8
. . . . . . . . . . .
Silverlight and the DOM. . . . . . . . . . . . . . . . . . . . . . . . 129 XAML FindName in JavaScript . . . . . . . . . . . Defining In-Line XAML via JavaScript . . . . . . Dynamic Creation of XAML Objects . . . . . . . JavaScript and Checkerboard Patterns . . . . . Checkerboard Patterns and Color Gradients . Updating Objects via HTML BUTTON Events . Generating Random Rectangles . . . . . . . . . . Key Constructs . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 7
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
153 155 159 163 165 167 171 177 178 180 181
Silverlight and Complex Graphics . . . . . . . . . . . . . . . . . 183 Mathematical Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183 Generating Sine-Based Petals. . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 Generating a Sine-Based Wireframe Effect . . . . . . . . . . . . . . . . . . 188
ix
x
Contents Multi-Fixed Point Mesh and Archimedean Spirals . Simulating 3D Effects with a Steiner Equation . . . Key Constructs . . . . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 9
. . . . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
196 202 208 208
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
209 211 218 229 234 240 244 245
Silverlight Animation Effects . . . . . . . . . . . . . . . . . . . . 247 Animation Effects via Storyboard Objects. . Rectangles and Animation. . . . . . . . . . . . . Be´zier Curves and Animation. . . . . . . . . . . Rotating a Rectangle Animation . . . . . . . . Rectangles and Multiple Animation Effects Chained Animation Effects . . . . . . . . . . . . Color Animation Effects . . . . . . . . . . . . . . Point Animation Effects. . . . . . . . . . . . . . . Animating Opacity in JPEG Images . . . . . . Silverlight/XAML Keyframes . . . . . . . . . . . . Silverlight/XAML Linear Keyframe . . . . . . . Silverlight/XAML Discrete Keyframe . . . . . . Silverlight/XAML Spline Keyframe . . . . . . . Key Constructs . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 11
. . . .
Bar Charts, Line Graphs, and Pie Charts . . . . . . . . . . . . 209 Rendering Homogeneous Bar Sets . . . . . . Rendering Simple Bar Charts . . . . . . . . . . Rendering Mouse-Enabled 3D Bar Charts . Rendering Gradient Bar Charts . . . . . . . . Rendering a Line Graph . . . . . . . . . . . . . Rendering Elliptic Pie Charts . . . . . . . . . . Key Constructs . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 10
. . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
248 248 251 252 255 257 259 261 263 265 265 268 270 273 275
Images, Audio Files, and Video Files . . . . . . . . . . . . . . . 277 Rendering JPEG Images . . . . . . . . . . . . . . . . . . Rendering Clipped JPEG Images. . . . . . . . . . . . Applying Transforms to JPEG Images . . . . . . . . Reflected JPEG Images. . . . . . . . . . . . . . . . . . . Image Brushes and JPEG Images . . . . . . . . . . . Mouse-Enabled JPEG Images . . . . . . . . . . . . . . Simple Mouse-Over Effects with JPEG Images. . Mouse-Over Effects with Multiple JPEG Images Animation with JPEG Images . . . . . . . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
277 279 281 282 284 285 289 294 299
Contents Playing MP3 Audio Files . Playing WMV Video Files. Key Constructs . . . . . . . . Summary . . . . . . . . . . . .
Chapter 12
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
301 302 306 308
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
309 313 318 324 330 331
Introduction to Scripting Languages . . . . . . . . . . . . . . . 333 Setting Up Python on Your Machine . . . . . . . . . Interactive Python . . . . . . . . . . . . . . . . . . . . . . . Scalar Variables in Python . . . . . . . . . . . . . . . . . Python Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . Python Dictionaries . . . . . . . . . . . . . . . . . . . . . . Sorting Elements in a Python Dictionary . . . . . . String Manipulation in Python. . . . . . . . . . . . . . Concatenating Strings and Numbers in Python. . The list and join Commands in Python. . . . . . . . Loops and Conditional Statements in Python . . . Comparing pass, break, and continue in Python. Packages and import Statements . . . . . . . . . . . . Setting Up Ruby on Your Machine . . . . . . . . . . Interactive Ruby . . . . . . . . . . . . . . . . . . . . . . . . String Variables in Ruby . . . . . . . . . . . . . . . . . . Converting between Classes . . . . . . . . . . . . . . . Using for and while Loops in Ruby . . . . . . . . . . Conditional Logic in Ruby . . . . . . . . . . . . . . . . . Arrays and Iterators in Ruby . . . . . . . . . . . . . . . Hashes in Ruby . . . . . . . . . . . . . . . . . . . . . . . . . Defining Functions in Ruby . . . . . . . . . . . . . . . . Defining Classes in Ruby . . . . . . . . . . . . . . . . . . Key Constructs . . . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 14
. . . .
Silverlight/JavaScript Animation . . . . . . . . . . . . . . . . . . 309 Simple Animation Effects . . . . . . . Checkerboard Animation. . . . . . . . Bouncing Rectangle Animation . . . Multiple Bouncing Balls Animation Key Constructs . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . .
Chapter 13
. . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
334 335 336 337 338 339 339 341 341 342 343 344 345 346 346 347 348 349 350 351 352 353 354 356
Silverlight and Scripting Languages . . . . . . . . . . . . . . . 359 Generating XML from Text Files . . . . . . . . . . . . . . . . . . . . . . . . . 360 Generating a Silverlight Document with Python. . . . . . . . . . . . . . 360
xi
xii
Contents Generating Bar Sets with Python . . . . . . . . . . Generating a Silverlight Document with Ruby Generating Bar Sets with Ruby . . . . . . . . . . . Generating a Silverlight Document with Perl . Generating Bar Sets with Perl . . . . . . . . . . . . Silverlight and IronPython . . . . . . . . . . . . . . . Updating a Rectangle in IronPython . . . . . . . IronPython and Mouse Events . . . . . . . . . . . . IronPython and Dynamic Object Creation . . . IronPython and Dynamic Checkerboards . . . . IronPython and Dynamic Graphics . . . . . . . . . Key Constructs . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 15
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
362 364 365 367 368 370 372 373 377 379 381 384 384
Silverlight and Java . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 Installing a Java SDK . . . . . . . . . . . . . . . . . . . . . Installing the Tomcat Servlet Container . . . . . . . Creating Java Web Applications. . . . . . . . . . . . . Deploying Java Web Applications . . . . . . . . . . . Details of Step 1 . . . . . . . . . . . . . . . . . . . . . Details of Step 2 . . . . . . . . . . . . . . . . . . . . . Details of Step 3 . . . . . . . . . . . . . . . . . . . . . Details of Step 4 . . . . . . . . . . . . . . . . . . . . . The web.xml Configuration File. . . . . . . . . . . . . DisplayXamlServlet.java . . . . . . . . . . . . . . . . . . . Invoking the Java Servlet DisplayXamlServlet . . . Generate Silverlight Documents in Java Servlets . Silverlight and JSP Files . . . . . . . . . . . . . . . . . . . Key Constructs . . . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 16
. . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
387 388 389 391 391 392 392 392 392 394 397 398 407 409 409
Supplemental Silverlight/JavaScript Samples . . . . . . . . . 411 Archimedean Cubic Be´zier Curves . . . Ellipses and Ribbed Effects . . . . . . . . Creating Pin-Cushion Effects . . . . . . . Ellipses with Multiple Color Gradients Key Constructs . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
413 417 422 426 434 434
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
Introduction
Read This First: Silverlight Coding Styles and Other Key Points This Introduction provides consolidated details for a variety of topics that you will be exposed to as you learn Silverlight. One topic of particular importance is the four-file coding style (rather than three) that is adopted in this book, along with the rationale for the file-naming convention. You will also learn about the terminology that is used and variations that you may encounter in other Silverlight books. This Introduction will address issues that might arise and offer you alternatives that can assist you in resolving those issues. The Silverlight code for this book was developed and tested on a 2GHz HP Pavilion laptop with the Vista operating system. Consequently, this Silverlight code will work on any machine that supports Silverlight 1.1 ‘‘alpha refresh’’ (or later). Warning Please remember that the Silverlight code in this book was verified for Silverlight 2.0 alpha, and if you upgrade (or install) Silverlight 2.0 beta, you may discover that samples in Chapters 10 and 14 no longer work. If this happens, please check the download site (www.courseptr.com/downloads) for code fixes.
As you probably know, Silverlight is available for multiple browsers and operating systems, yet people have different versions of operating systems and patches applied to their systems. Consequently, it’s possible that you will encounter issues that impede your progress. For example, you might be able to open XML xiii
xiv
Introduction
documents in one text editor but not in another. As another example, you might encounter a situation in which it is advantageous for you to use Firefox instead of Internet Explorer. In short, this Introduction describes potential issues that you may encounter, along with an explanation of how the recommended solutions are beneficial to you.
The Four Files for Silverlight Applications One of the important goals of this book is to show you how to write Silverlight code in a manner that will reduce the amount of code maintenance in the future. In essence, this is the rationale for the four-file coding convention. Let’s look at a simple Silverlight application named Test that will display the text string Hello Silverlight. The naming convention (and location) that will be used throughout this book for the four files for the Silverlight application Test is shown here: (created by you for each application)
n
Test.html
n
js/Silverlight.js
n
js/CreateSilverlightTest.js
n
xaml/Test.xml
(Microsoft provides this file) (created by you for each application)
(created by you for each application)
The HTML file Test.html includes a reference to the JavaScript file Silverlight.js, which Microsoft provides, and CreateSilverlightTest.js, which you write (and which consists of a single JavaScript function). When you launch the HTML file Test.html in a browser, the HTML code invokes the single JavaScript function defined in CreateSilverlightTest.js, which in turn calls another JavaScript function in Silverlight.js. Thus, the file CreateSilverlightTest.js serves as a ‘‘layer of indirection’’ between the HTML file Test.html and the JavaScript file Silverlight.js that Microsoft provides. In case you are thinking that this extra indirection makes the Silverlight application more complicated (as well as requiring an additional JavaScript file), you have a valid concern. However, this technique will ‘‘shield’’ your HTML code from changes in future releases of Silverlight that might necessitate changes in your code.
Introduction
The contents of CreateSilverlightTest.js are shown here: function createSilverlight() { Silverlight.createObjectEx({ source: ’xaml/Test.xml’, parentElement:document.getElementById("Ag1Host"), id:"Ag1", properties:{width:’500’, height:’500’, background:’#00FFFFFF’, isWindowless:’true’, framerate:’24’, version:’0.90.0’}, events:{onError:null, onLoad:onLoad}, context:null}); }
The JavaScript function createSilverlight acts as a ‘‘wrapper’’ function that invokes the Silverlight-specific function Silverlight.createObjectEx (defined in Silverlight.js) by specifying a collection of name/value pairs that are explicitly linked to elements in the HTML file Test.html. The createSilverlight function references the XML document Test.xml via the following code snippet: source: ’xaml/Test.xml’,
The preceding code snippet is what enables a ‘‘three-way binding’’ of Test.html, CreateSilverlightText.js, and Test.xml. This binding is what enables the HTML file Test.html to reference Silverlight/XAML objects that are defined in Test.xml. There are three additional points to notice in the JavaScript function createSilverlight. First, the parent element is Ag1Host, which is the name of an element in the HTML file Test.html. Second, the id of the newly created Silverlight object has the value Ag1. Third, the onLoad attribute has the value onLoad, which means that the JavaScript function onLoad in the HTML file Test.html will be executed when Test.html is loaded into a browser. The contents of the HTML file Test.html are shown here:
xv
xvi
Introduction Silverlight Graphics
createSilverlight();
The HTML file Test.html contains a DIV element whose id attribute has the value Ag1Host. This DIV element serves as the parent element for the Silverlight object that is created in the JavaScript function createSilverlight (defined in CreateSilverlightTest.js) via the following code snippet: parentElement:document.getElementById("Ag1Host")
The contents of the XML document Test.xml are shown here:
The following point has been made already, but its importance bears repetition: you can use three files instead of four by copying Silverlight code from CreateSilverlightTest.js into the HTML file Test.html, but please remember that future releases of Silverlight might necessitate changes to the Silverlight code that you copied into the HTML file; therefore, code maintenance can become
Introduction
more complicated. For this reason, this book uses the four-file convention for creating Silverlight applications.
XML File-Name Extension: .xml versus .xaml There are no substantive advantages to storing XAML files with a .xaml extension, and there are at least three problems with using a .xaml extension: n
In some cases, Vista users will get rendering effects that are wrong when they open the XAML files using Internet Explorer or Firefox.
n
In other cases, Vista users will get errors when they open the XAML files in Internet Explorer or Firefox.
n
Users cannot open the XAML files in Internet Explorer to view the contents of the XML files.
The first problem is the worst, because users will be misled by a WPF-based rendering of their graphics code; in other words, they will not have a WYSIWYG environment that renders their Silverlight/XAML code correctly. The second problem may appear cosmetic, but users can erroneously conclude that something is wrong with the XAML code, when in fact it is valid. The third problem also prevents users from opening the XAML content in a browser and then copying the content into a text file, which is one workaround to the single-line display issue with Notepad. The first two problems are guaranteed to happen for Vista users and all XP users who have version 3.0 (or later) of the .NET Framework 3.0 installed. The recommended solution is to store the XML files with a .xml extension. For the reasons outlined in this section, the Silverlight examples in this book store XML files with a .xml extension instead of a .xaml extension.
Objects and Properties The Microsoft SDK refers to objects and object properties in Silverlight, whereas other technologies (such as SVG) use the term element and element attributes. Some Silverlight books prefer to use shape or control instead of object. Other books use a mixture of object and element.
xvii
xviii Introduction
This book will use object instead of element when referring to Silverlight objects, and attribute instead of property.
Internet Explorer versus Firefox Internet Explorer displays an information bar that prevents the display of certain content when malicious code is possible. There are instructions available for disabling the information bar, but the instructions do not appear to work correctly. If you have problems, the recommended solution is to use Firefox instead of Internet Explorer.
Text Editors Notepad is a standard text editor that is available on almost all Windows versions, but it’s possible that the XML documents will not be rendered correctly in Notepad. When you open a file in Notepad, navigate to Format, Word Wrap to ensure that word wrap is on. Then close Notepad and open the file again in Notepad. If the problem persists, you can open the XML document in a browser and then copy/paste the code into Notepad. If you prefer a simpler alternative, use another editor, such as WordPad, to open the XML document. You can also use other non-Microsoft text editors such a Lemmy (which is a Windows-based ‘‘port’’ of the Unix vi text editor). You can search the Internet for other text editors to find the one that suits you best. Yet another alternative is to use an XML editor, such as XMLSpy. The advantage of XML editors is that they allow you to ‘‘expand’’ and ‘‘collapse’’ the Silverlight objects in an XML document. Microsoft also has an XML editor called XML Notepad.
Adobe SVG Viewer Support Adobe currently provides an SVG viewer as a plug-in for Internet Explorer. The plug-in is available in multiple languages and for different hardware platforms at http://www.adobe.com/svg/viewer/install/. Adobe will discontinue support for this plug-in on January 1, 2009.
chapter 1
Introduction to Silverlight This chapter introduces you to some of the fundamental concepts that underlie virtually all of the Silverlight and XAML code in this book. If you are an experienced XAML or SVG developer, you can skim through this chapter to discern the syntactic differences between XAML and SVG. The first part of this chapter provides a brief description of Silverlight, several URLs where you can download tools for Silverlight, and some differences between Silverlight and SVG. The second part of this chapter provides the information for downloading and installing Silverlight, followed by a description of the structure of a Silverlight application. The third (and largest) part of this chapter provides an introductory view of Silverlight/XAML documents and the coordinate system that will assist you in visualizing the Silverlight/XAML code for rendering two-dimensional geometric objects such as lines, rectangles, and polygons. Although the subject of this book is Silverlight and XAML, you will also find many side-by-side SVG documents that illustrate how to create a similar visual effect as the corresponding Silverlight/XAML code. However, keep in mind that the feature set of SVG differs from that of Silverlight/XAML, which means that the SVG code is an approximation of the corresponding Silverlight/XAML code. In particular, you will notice the difference in functionality when you learn
1
2
Chapter 1
n
Introduction to Silverlight
about linear color gradients and radial color gradients, which are the topic of Chapter 2, ‘‘Colors, Linear Gradients, and Radial Gradients.’’ As you probably know, Silverlight/XAML is an evolving product. As this book goes to print (early 2008), Silverlight has been available for less than a year. Hence, Silverlight does not support some of the features that are available in SVG. For example, SVG supports a rich, complex, and powerful set of filters, whereas Silverlight does not provide any support for filters. Watch for announcements from Microsoft regarding enhancement of existing features and the addition of new functionality in future releases of Silverlight. Note Please read the Introduction (‘‘Read This First: Silverlight Coding Styles and Other Key Points’’) on pages xiii--xviii, because it contains important configuration-related information that describes potential issues that you might encounter, and the recommended solutions.
Finally, all the code for all the chapters in this book can be found on the publisher’s Web site at www.courseptr.com/downloads. You can access the downloads by title, author name, or ISBN.
What Is Silverlight? Silverlight is a browser plug-in that was released during the first half of 2007, and it is available for Internet Explorer, Firefox on Windows, and Safari on Macintosh. Silverlight was originally called WPF/E (short for WPF everywhere), and it provides a subset of the functionality of WP/F. Silverlight is supported in Internet Explorer 6.x/7.x and Firefox 1.5/2.0. On Macintosh machines, you will need version 10.4.8 (or higher) of the O/S. Note that all references to ‘‘Silverlight’’ in this book refer to Silverlight/XAML, and not WPF/XAML. Silverlight 1.0 (the first release) provides XAML-based graphics capabilities, but it lacks support for HTML-like widgets, such as buttons, lists, checkboxes, and so forth. Silverlight 1.1 Alpha Refresh (released in September 2007) enhances version 1.0 by providing support for the HTML-like widgets that are unavailable in version 1.0. Version 1.1 also supports IronPython and IronRuby, both of which are dynamic scripting languages. In December 2007, Silverlight 1.1 was renamed Silverlight 2.0 alpha. A beta release of Silverlight 2.0 will be available early in 2008. If you want to read a brief description (from Microsoft) regarding the advantages of Silverlight, navigate to http://www.microsoft.com/silverlight/install.aspx#1_0.
Silverlight versus SVG Warning Silverlight 2.0 is a beta product, and it’s possible that the Silverlight links in this book will change in the future. If any of these links are invalid, please go to Microsoft’s home page and search for the new link.
You can find useful information about Silverlight tools and resources by navigating to http://www.microsoft.com/silverlight/installation-win.aspx#4_0. You can find download information about the Silverlight 2.0 beta by navigating to http://www.microsoft.com/silverlight/resources/InstallationFiles.aspx?v=2.0.
Silverlight/XAML Naming Convention The names of XAML objects almost always start with an uppercase letter. For example, the name of the XAML object for a Silverlight/XAML rectangle object is Rectangle, and the name of the XAML object for a Silverlight/XAML ellipse object is Ellipse. Compare this naming convention with SVG, which uses lowercase tag names (and sometimes abbreviations) such as rect and ellipse. Additional details regarding these differences will be noted as they arise in the discussions that follow the code samples.
Silverlight versus SVG As you probably already know, Silverlight and SVG offer similar functionality, so the decision to use Silverlight over SVG (or vice versa) depends on your resource availability, technical requirements (current as well as future), and other relevant dependencies for your project. The following short list contains some features to consider when evaluating whether to use Silverlight or SVG: n
Native versus plug-in browser support
n
Level of SVG support in different browsers
n
Animation support
n
Support for filters (SVG only)
n
Built-in support for HTML-like widgets
n
Third-party support
Adobe’s SVG viewer can be used with Microsoft’s Internet Explorer, whereas the Firefox browser has built-in SVG support. If you need the ability to interact with
3
4
Chapter 1
n
Introduction to Silverlight
.NET, then Silverlight is mandatory. On the other hand, if you need filter-based visual effects, then only SVG provides such functionality. If you need built-in support for HTML controls, then Silverlight/XAML (version 1.1) has richer support for this type of functionality. Another point to keep in mind is that Adobe has announced its decision to no longer support an SVG viewer. This is a significant decision, because Adobe’s SVG viewer has been the de facto standard for many years. Although Firefox and Opera have made significant progress in terms of their support for SVG, and both are enhancing their support for SVG, they still lack the feature support of Adobe’s SVG viewer. Thus, you need to carefully weigh the most important factors to make the decision that will meet your project-related needs.
Downloading and Installing Silverlight For Windows-based machines, you need either Windows XP or Windows Vista for viewing Silverlight graphics. If you have Windows XP, you need to download and install additional software, including SP 2, before you install the Silverlight plug-in. If you have Windows Vista, your machine is already configured with some of the software that is required for a Windows XP machine. The recommended system configuration is available at http://msdn2.microsoft .com/en-us/silverlight/bb187401.aspx#config. The software prerequisites for Silverlight are available at http://silverlight.net/ getstarted. If you want to read the Microsoft FAQ for Silverlight, launch a browser session and navigate to http://www.microsoft.com/silverlight/#4_4. If you need to read the ‘‘Silverlight Deployment Guide’’ document, first navigate to http://www.microsoft.com/silverlight/#4_3 and then click on the link labeled ‘‘Silverlight Deployment Guide’’ to download this document. Other downloadable software packages that you can use with Silverlight (including Visual Studio 2008) are available at http://www.microsoft.com/ silverlight/#4_1. Although you do not need Microsoft Expression Blend 2 December release (2007) for this book, you can download this tool by navigating to http:// www.microsoft.com/downloads/details.aspx?FamilyID=65177E23-C116-475A9057-5A5071A379F6&displaylang=en.
Structure of a Silverlight Application
Finally, launch a browser session and navigate to http://www.microsoft.com/ silverlight/install.aspx#4_6. You either install Silverlight directly, or you can save the installer on your machine and then run the installer manually. If you want more detailed installation instructions, navigate to http://www.microsoft.com/silverlight/installation-win .aspx#4_7. After you complete this step, you will be ready to run the Silverlight code in this book.
Structure of a Silverlight Application If you have read the introduction, you know that the Silverlight code samples in this book involve four files, and the advantage of this approach will be apparent as the HTML file and XML document become large and complex. Whenever you want to launch a Silverlight application presented in this book, simply double-click on the appropriate HTML file, which is always located in the chapter-level directory. In addition to the main directory, each chapter contains three subdirectories, as shown here: ch1/ js xaml svg
This directory structure is not mandatory; however, it is an intuitive structure for the location of Silverlight-related files. This structure will be used in all the examples in this book, but you are free to modify the directory structure; just make sure you change the paths in the HTML files to reflect the new relative paths of your files. The directory ch1 contains HTML files, and the js subdirectory contains the file Silverlight.js, along with other JavaScript files that are specific to your Silverlight application (as explained in the introduction). The xaml subdirectory contains XML documents, and the svg subdirectory contains the corresponding SVG files that generate the graphics effect that is comparable to the Silverlight/ XAML graphics. For simplicity, the HTML file and the referenced XML document have the same name. As an example, the HTML file Rect1.html is located in
5
6
Chapter 1
n
Introduction to Silverlight
the directory ch1, the XML document Rect1.xml is located in the xaml subdirectory, and the JavaScript file Silverlight.js is in the js subdirectory. In this chapter you will learn how to use Silverlight/XAML objects such as Rectangle, Path, and Polygon to define rectangles. You will also learn how to control the visual display of rectangles by specifying different values for attributes such as Fill, Stroke, StrokeThickness, and StrokeDashArray. As you will see, this book contains many comments regarding the differences between XAML and SVG. In case you didn’t already know, Silverlight/XAML, WPF/XAML, and SVG are very similar in what they can accomplish, yet their differences are more than cosmetic. This parallel commentary will help you understand how to convert code from XAML to SVG and vice versa. If you want to learn more about SVG, there are several books available, including one by the author of this book, called Fundamentals of SVG Programming: Concepts to Source Code (ISBN 1-58450-298-3).
A Minimal XAML Document Every Silverlight/XAML document must have a single outermost Canvas object that is the root (i.e., top-level) node of the document. All other nodes are child nodes of this root node. Listing 1.1 contains an example of a minimal Silverlight/ XAML document. Listing 1.1
A Minimal XAML Document
The Canvas object contains two so-called namespace attributes, both of which are mandatory. If you are unfamiliar with namespaces, you can find information on the Internet that describes namespaces in detail. In brief, you can think of a namespace as a resource that serves to differentiate the origin of different objects or objects. For example, an XML document can contain FirstName objects that are of different origins. However, in this book you can effectively ignore the technical purpose of namespaces without affecting your ability to understand Silverlight/XAML. Keep in mind that you will encounter different styles for displaying namespaces, but fortunately, these differences are purely stylistic. In other words, there is no
A Silverlight/XAML Rectangle
code-related difference among the styles, and the variances are purely cosmetic; they pertain solely to personal taste and preference. For example, here is another (equally valid) style:
Listing 1.2 illustrates another minimal Silverlight/XAML document that contains an empty Rectangle object. Listing 1.2
An Empty Rectangle
Both of the preceding documents are trivial because they do absolutely nothing of interest. In general, a Canvas object contains many XAML objects, and you can even include other Canvas objects inside the root Canvas object. The use of nested Canvas objects in a XAML document enables you to treat logically related objects as a single component, which can greatly simplify code maintenance. Incidentally, an example of an SVG ‘‘do-nothing’’ document is given here:
One difference between Silverlight/XAML and SVG is that every SVG document must contain the SVG svg element as its root node, which means that the svg element is also the parent node of all the other svg elements in the SVG document.
A Silverlight/XAML Rectangle The following example contains a complete Silverlight/XAML document with the code that displays a rectangle in Silverlight/XAML. As explained previously, the Silverlight/XAML examples in this chapter always consist of four files. The
7
8
Chapter 1
n
Introduction to Silverlight
Figure 1.1 A Silverlight/XAML rectangle.
HTML file in this section is Rect1.html, which means that it will reference the JavaScript files Silverlight.js and CreateSilverlightRect1.js in the js subdirectory and the XML document Rect1.xml in the xaml subdirectory. Later in this chapter you will learn about the coordinate system used by Silverlight/XAML (and also SVG), which will enable you to understand the logic that underlies the rendering of graphics objects in Silverlight/XAML. Now take a look at the simple rectangle displayed in Figure 1.1. The Silverlight/XAML document Rect1.xml in Listing 1.3 demonstrates how to draw a rectangle with a red border whose width is 200 pixels and whose height is 150 pixels. In addition, the upper-left vertex of this rectangle is the point 50,50. Listing 1.3
Rect1.xml
A Silverlight/XAML Rectangle
Navigate to the location of the HTML file Rect1.html and double-click on this file to render the rectangle that is defined in the XML document Rect1.xml. Now let’s examine the contents of Listing 1.3 in more detail. The first line specifies the Silverlight/XAML Canvas object and two xmlns namespace attributes for the document:
Note that the first two lines often appear as a single line because whitespace is insignificant. The next line in Rect1.xml contains a comment:
You can also include multiline comments like this:
The next line specifies the beginning of the Silverlight/XAML Rectangle object:
The last two lines close the definitions of the Rectangle object and the Canvas object:
That’s all there is to defining a Silverlight/XAML Rectangle object. The corresponding code for an SVG document containing an SVG rect element is illustrated in Listing 1.4. Listing 1.4
Rect1.svg
As shown in Listing 1.4, SVG uses the attributes x, y, width, and height, which correspond to the XAML attributes Canvas.Left, Canvas.Top, RectangleTop, Width, and Height, respectively. Another difference between Silverlight/XAML and SVG is that SVG allows you to specify style-related attributes in two ways: as a list of colon-separated name/value pairs, or as concatenated name/value pairs using a semicolon (;) as a delimiter. Thus, either of the following is permitted in SVG: style="stroke:red;stroke-width:5" stroke="red" stroke-width="5"
Keep in mind that the concatenated style in SVG works only in IE 5.x or higher; in other browsers (including Firefox) you must specify each attribute separately.
The Silverlight/XAML Coordinate System
The Silverlight/XAML Coordinate System Perhaps you remember the Cartesian coordinate system from one of your high school math classes. The Cartesian coordinate system (also called the Euclidean coordinate system) allows you to specify any point in the Euclidean plane by means of a pair of numbers. The first number represents the horizontal value, and the second number represents the vertical value. Often you’ll see a pair of perpendicular line segments that represent the Cartesian coordinate system. The horizontal axis is labeled the x-axis, and positive values on the x-axis are to the right of the vertical axis. The vertical axis is labeled the y-axis, and positive values on the y-axis are above the horizontal axis. The origin is the intersection point of the x-axis and the y-axis. The situation is almost the same in the XAML coordinate system. The x-axis is horizontal, and the positive direction is toward the right. The y-axis is vertical, but the positive direction is downward. As you can see, the positive y-axis points in the opposite direction of most graphs in a typical mathematics textbook. When we draw our graphics images, we’ll have to take this fact into account. This detail is easy to forget, and often it is the underlying cause of incorrect images. Two more details about the XAML coordinate system: The origin is the upperleft corner of the screen, and the unit of measurement is the pixel, so the largest visible display is usually 1024 728. Navigate to the location of the HTML file CoordinateSystem1.html and doubleclick on this file to render the two line segments and the four circles that are defined in the XML document CoordinateSystem1.xml, as shown in Figure 1.2. Note that the coordinate system has been shifted downward and to the right to render the horizontal and vertical axes more clearly.
Figure 1.2 The XAML coordinate system.
11
12
Chapter 1
n
Introduction to Silverlight
Based on the definition of the XAML coordinate system, you can see that the four circles in CoordinateSystem1.xml are rendered in Figure 1.2 in the manner described here: n
Point (50, 50) is 50 pixels to the right and 50 pixels downward.
n
Point (200, 50) is 200 pixels to the right and 50 pixels downward.
n
Point (50, 100) is 50 pixels to the right and 100 pixels downward.
n
Point (200, 100) is 200 pixels to the right and 100 pixels downward.
Rendering Polygons with Polygon Objects You already know that the Silverlight/XAML Rectangle object defines a rectangle. The Polygon object can render arbitrary quadrilaterals, which include rectangles as a special case. In addition, the Polygon object enables you to render polygons with any number of sides. (Don’t forget that a triangle is a polygon with three sides.) Since you can specify an arbitrary number of vertices, the Polygon object is extremely versatile. The XAML document Polygon1.xml in Listing 1.5 uses the Silverlight/XAML Polygon object to render a triangle. Listing 1.5
Polygon1.xml
Navigate to the location of the HTML file Polygon1.html and double-click on it to render the triangle that is defined in Polygon1.xml. The Polygon object contains a list of vertices (where each vertex specifies a point in the Silverlight/XAML coordinate system) that represents a polygon in the Euclidean plane. Note that a polygon is a closed path of connected line segments in which the coordinates of the final vertex coincide with those of the first vertex in a path. You can also use the Polyline object to render a polygon. Just remember that the last vertex in the list must be the same as the first vertex in the list; otherwise the rendered component will not look like a polygon.
Rendering Rectangles with Path Objects
The Polygon object is useful in situations where you need to modify a polygon. For example, a rectangle that is defined via a Silverlight/XAML Polygon object can be modified during animation to render a quadrilateral. Keep in mind, though, that while you can use the Polygon object for defining a rectangle, the purpose of your code is clearer if you use the Rectangle object for rendering a rectangle. The equivalent SVG polygon object (with the exception of the gradient attribute) is virtually the same, as shown in the code fragment here: style="fill:red;stroke:blue;fill:red;stroke-width:4"/>
You can experiment with the code in Listing 1.5 by adding any number of new points, which will also help you become more comfortable with the Silverlight/ XAML Polygon object.
Rendering Rectangles with Path Objects The Silverlight/XAML Path object is extremely powerful and can be used for rendering many geometric objects, including rectangles. This object is useful for defining complex graphics images that contain curvilinear components. Defining a rectangle with this object is useful in situations such as animation, where you need to modify the vertices of the rectangle to render a quadrilateral or a parallelogram. The Silverlight/XAML document PathRectangle1.xml in Listing 1.6 uses the XAML Path object to render a rectangle. Listing 1.6
PathRectangle1.xml
The Path object is extremely powerful and flexible; not only can you generate polygons, you can also specify elliptic arcs, quadratic Be´zier curves, and cubic
13
14
Chapter 1
n
Introduction to Silverlight
Be´zier curves (as you will learn in Chapter 4, ‘‘Be´zier Curves and Color Gradients’’). Notice the syntax of the points in a path: Data="M20,20 220,20 220,170 20,170 20,20"
The preceding path definition can be translated as follows: ‘‘move to the point 20,20; draw a line segment from the point 20,20 to the point 220,20; draw a line segment from the point 220,20 to the point 220,170; draw a line segment from the point 220,170 to the point 20,170; draw a line segment from 20,170 to the point 20,20.’’ The uppercase M refers to an absolute point. You can use a lowercase m if you need to specify a point in the plane that is relative to a preceding point (i.e., the point that is to the immediate left of the current point). The same logic applies to uppercase L and lowercase l when rendering line segments. Note that large value for the StrokeThickness attribute in the Silverlight/XAML Path object can create precise corners. Hence, you may need to experiment with different values for the StrokeThickness attribute to produce a visual effect that is closer to the one that you want. If you are creating rectangles with the Path object, consider using the Silverlight/ XAML Line object, because it allows you to control the line join of line segments via the StrokeLineJoin attribute. You can set the value of this attribute value to Bevel, Miter, or Round. Experiment with different values for this attribute to see if it helps create the desired effect. The equivalent SVG path element is listed here:
Rendering Rectangles with Line Objects The Silverlight/XAML Line object can be used for each of the four sides of a rectangle to define the rectangle itself. A line segment is determined by two points in the Silverlight/XAML plane, each of which has an x-coordinate and a y-coordinate. The Silverlight/XAML document LineRectangle1.xml in Listing 1.7 uses the Silverlight/XAML Line object to render a rectangle.
Rendering Rectangles with Line Objects
Listing 1.7
LineRectangle1.xml
The Silverlight/XAML Line object defines a line segment whose end-points are given by the points with coordinates X1,Y1 and X2,Y2. You can define a rectangle by means of four Line objects, where each Line object specifies the coordinates of the two vertices of one of the four sides of the rectangle. Since more code is required to specify a rectangle in terms of Line objects, and your code becomes less intuitive, it’s probably better to use the Rectangle object for rendering rectangles and use the Line object for rendering non-rectangular polygons (e.g., quadrilaterals). The equivalent set of SVG line elements for rendering a rectangle is listed here:
15
16
Chapter 1
n
Introduction to Silverlight
Rendering Rectangles with a Shadow Effect Figure 1.3 displays a rectangle with a shadow effect. The Silverlight/XAML document RectShadow1.xml in Listing 1.8 uses the Rectangle object to render a rectangle with a shadow effect. Listing 1.8
RectShadow1.xml
Figure 1.3 A rectangle with a shadow effect.
Rendering Rectangles with a Shadow Effect
The Silverlight/XAML code in Listing 1.8 demonstrates how easy it is to create a shadow effect by rendering two rectangles: The background rectangle is black, and the foreground rectangle is red. The background rectangle has a (+,+) location relative to the foreground rectangle; i.e., it is shifted downward and to the right. The other three possibilities for the background rectangle location are (+,–), (–,+), and (–,–) with respect to the foreground rectangle. These other locations provide different shadow effects that create the impression of different view positions. Silverlight/XAML objects appear in the order in which they are defined in XML documents, in a ‘‘top-to-bottom’’ fashion. Thus, the first Silverlight/XAML rectangle is rendered, followed by the second rectangle. Thus, if the Rectangle objects overlap, the second one will be placed on top of the first rectangle. However, you can change the default rendering (stacking) order by using the Canvas.ZIndex attribute. The default value for this starts at 1 and increases sequentially for each subsequent Silverlight/XAML object. If you want the second Rectangle object to be rendered before the first Rectangle object, you need to change the code in Listing 1.8 as shown here:
The preceding comments discussed Rectangle objects, but they are applicable to all other Silverlight/XAML objects as well. Listing 1.9 displays the equivalent SVG code that corresponds to the code in the XML document RectShadow1.xml. Listing 1.9
RectShadow1.svg
17
18
Chapter 1
n
Introduction to Silverlight
Rendering Rectangles with RectangleGeometry Silverlight provides support for the RectangleGeometry object, which is yet another way for defining rectangles in Silverlight. The Silverlight/XAML document RectGeometry1.xml in Listing 1.10 uses the RectangleGeometry object to render a rectangle. Listing 1.10
RectGeometry1.xml
Listing 1.10 contains two Path objects that render a rectangle and a line segment. The first Path object contains a RectangleGeometry object as a child object, whereas the second Path object contains a LineGeometry object as a child object. The rectangle is specified via the following code fragment:
Rendering Triangular Wedges with Shading
The line segment is specified via the following code:
Listing 1.10 provides a brief introduction to the Path object, which is a very versatile object that will be described in much greater detail later in this book.
Rendering Triangular Wedges with Shading Figure 1.4 displays a triangular wedge that is based on a Silverlight/XAML Polygon object. The Silverlight/XAML document TriangularWedge1.xml in Listing 1.11 uses the Polygon object to render a triangular wedge. Listing 1.11
TriangularWedge1.xml
Figure 1.4 A triangular wedge.
19
20
Chapter 1
n
Introduction to Silverlight
The Silverlight/XAML code in Listing 1.11 contains two Polygon objects: The first one renders a red triangle, and the second one renders a black parallelogram on the left side of the red triangle. The parallelogram and triangle share a common side; the other parallel sides of the parallelogram are tilted upward slightly, thereby creating a three-dimensional shading effect. Usually an angle of 208 or so produces the best shading effect, but feel free to experiment with different angles of elevation until you find one that suits your preferences. Listing 1.12 displays the equivalent SVG code. Listing 1.12
TriangularWedge1.svg
Nested Canvas Objects Earlier in this chapter you learned that the root-level Canvas object can contain other Canvas objects, which enables you to treat logically related objects as a single component. This functionality is very useful when you need to treat a collection of Silverlight/XAML objects as a single logical entity. For example, suppose you want to create artwork that consists of a house and background scenery. You can use one Canvas object for the XAML objects that render the house and another Canvas object for the background scenery. If you need to change the location of the house or the background, simply change the location of the corresponding Canvas object. Moreover, you can copy/paste an existing house to create a new house.
Nested Canvas Objects
Figure 1.5 XAML objects in different Canvas objects.
As an illustration, Figure 1.5 displays a Polygon object that is contained in a Canvas object and two rectangles that are contained in a second Canvas object. Both of these Canvas objects are child objects of a root-level Canvas object. The Silverlight/XAML document NestedCanvases1.xml in Listing 1.13 defines a root-level Canvas object that contains two nested Canvas objects to render a polygon and two rectangles. Listing 1.13
NestedCanvases1.xml
21
22
Chapter 1
n
Introduction to Silverlight
Listing 1.13 contains a root-level Canvas object that defines two other Canvas objects as child nodes. The first Canvas child object contains a polygon, and the second Canvas child object defines two rectangles. There is no restriction on the number of nested Canvas objects that you can define; however, they must all be child objects of a single top-level Canvas object. Listing 1.14 displays the SVG code that corresponds to the Silverlight/XAML code in Listing 1.13. Listing 1.14
Nested SVG Elements
...
Listing 1.14 contains an SVG element that has two SVG subelements. You can think of an SVG element as a counterpart to the Silverlight/XAML Canvas object. Note that the top-level object in Silverlight/XAML is a Canvas object (which can contain any number of nested Canvas objects), whereas the top-level element in SVG is the element, which can contain any number of SVG subelements.
Key Constructs A rectangle can be rendered using any of the following Silverlight/XAML snippets:
Summary
Summary This chapter covered the following topics that form the basis for Silverlight/ XAML graphics images in subsequent chapters: n
The Silverlight/XAML coordinate system
n
The Rectangle object for drawing rectangles
n
The Path object for drawing rectangles
n
The Rectangle object for creating 3D shadow effects
n
The Path object for drawing triangular wedges
23
This page intentionally left blank
chapter 2
Colors, Linear Gradients, and Radial Gradients The first part of this chapter contains an introduction to colors and shows you four ways to represent colors in Silverlight/XAML. The use of color is of paramount importance for displaying graphics images, and you need to know how to use standard colors and their many subtle shades. The second part of this chapter describes linear gradients and radial gradients in Silverlight/XAML, with code samples that illustrate how to use color gradients to create visually appealing graphics effects. The code samples in this chapter use Silverlight/XAML objects such as rectangles and polygons. Linear gradients and radial gradients are simple to define, yet they are extremely powerful in terms of the visual effects that are possible in Silverlight. The examples in this chapter involve rectangles and polygons so that you can focus on understanding the details of linear and radial gradients. In later chapters, you will see examples of using linear and radial gradients with ellipses and elliptic arcs, as well as more sophisticated geometric objects, such as quadratic and cubic Be´zier curves. Please keep in mind that the code samples presented in this book pertain to the XML documents that are located in the xaml subdirectory of each chapter, as described in the section ‘‘Structure of a Silverlight Application’’ in Chapter 1, ‘‘Introduction to Silverlight.’’
25
26
Chapter 2
n
Colors, Linear Gradients, and Radial Gradients
Colors and Their Components Color is a fundamental aspect of graphics. Imagine, if you can, what graphics or art would be like without any color. Apart from watching film noir, could anyone look forward to such an impoverished state of affairs? In the Silverlight/XAML world, a color can be defined in four ways. One way is an (R,G,B) triplet of base-10 integers, which specifies values for its red, green, and blue components, respectively. For example, the color red is represented in Silverlight/XAML as (255,0,0). The values for R, G, and B are independent of each other, and each is a decimal integer between 0 and 255. Consequently, there are 256 256 256 = 16,777,216 possible color combinations. The human eye cannot distinguish between every pair of possible colors, which means that interesting shading effects can be achieved. The color white has all colors present, and the color black is the absence of all color. Some common colors and their (R,G,B) definitions are listed here: White
(R,G,B) = (255,255,255)
Black
(R,G,B) = (0,0,0)
Red
(R,G,B) = (255,0,0)
As the values of R, G, and B in the (R,G,B) triplets decrease from a maximum of 255 to a minimum of 0, the associated color will darken. This behavior is consistent with the fact that white is (255,255,255) and black is (0,0,0). A second way to specify Silverlight/XAML colors involves listing the relative weights of the (R,G,B) triplets as a percentage between 0 and 100. For example, the color red is represented in Silverlight/XAML as rgb(100%,0%,0%). A third way to specify XAML colors involves a string of six hexadecimal digits. The Silverlight/XAML code in this book uses hexadecimal strings and the standard color names. For example, the string FF0000 represents the color red. Notice that the first pair of hexadecimal digits (FF) is the hexadecimal representation of the number 255. The other two pairs of hexadecimal digits correspond to the G component and the B component, respectively. For example, the Silverlight/XAML color with (R,G,B) values of (128,96,48) corresponds to the Silverlight/XAML color 806030.
Standard Color Names
The fourth way of specifying Silverlight/XAML colors involves using English names for colors, which is the subject of the next section. If you want help in converting between decimal and hexadecimal values, an online converter is available at http://www.easycalculation.com/hex-converter.php.
Standard Color Names Colors can be defined in terms of their (R,G,B) components. A short list of common colors is provided here. Blue
(0,0,255)
Green
(0,255,0)
Magenta
(255,0,255)
Orange
(255,128,0)
Pink
(255,175,175)
Red
(255,0,0)
Yellow
(255,255,0)
LightGray
(192,192,192)
DarkGray
(64,64,64)
Gray
(128,128,128)
Black
(0,0,0)
White
(255,255,255)
Your code will be more intuitive (and more legible) if you use the well-known name for a standard color instead of its corresponding hexadecimal value. The vast majority of colors do not have a well-known name, which means that you have no choice but to use the nonintuitive representation of the color in question. Regardless of the method you use for specifying colors, Silverlight/XAML
27
28
Chapter 2
n
Colors, Linear Gradients, and Radial Gradients
enables you to create rich visual images easily with subtle shading effects. To illustrate the techniques for specifying color, the following Silverlight/XAML code fragments demonstrate four different ways of rendering a blue rectangle with the Silverlight/XAML Rectangle object:
Rendering a Checkerboard Grid Figure 2.1 displays a checkerboard pattern via XAML Rectangle objects.
Figure 2.1 A checkerboard pattern.
The Silverlight/XAML document CheckerBoard1.xml in Listing 2.1 demonstrates how to render a 2 2 checkerboard pattern. Listing 2.1
CheckerBoard1.xml
Rendering a Checkerboard Grid
Listing 2.1 renders four rectangles in a 2 2 checkerboard pattern. The top row consists of the first two Rectangle objects, and the bottom row consists of the last two Rectangle objects. The four rectangles have the same values for the Width and Height attributes (in fact, the rectangles are also squares). The position of each rectangle is determined by the values of Canvas.Left and Canvas.Top. The equivalent SVG code is illustrated in Listing 2.2. There are two techniques for rendering a 2 2 checkerboard pattern in SVG. The first method (which is similar to Listing 2.1) involves specifying the values of the SVG x and y attributes in order to position each rectangle, because these two attributes are analogous to the Silverlight/XAML attributes Canvas.Left and Canvas.Top, respectively. The second technique (illustrated in Listing 2.2) renders one rectangle inside an SVG g element; this rectangle references an SVG pattern element that is defined in an SVG defs element. This type of indirection is very powerful, and it enables you to produce complex yet compact SVG code. Perhaps a future version of Silverlight/ XAML will support this feature, which is currently available only in SVG. Listing 2.2
Checkerboard1.svg
Listing 2.2 contains four SVG rect elements, the first of which is shown here:
SVG uses rect, width, and height instead of Rectangle, Width, and Height, respectively. In addition, SVG uses x and y instead of Canvas.Left and Canvas.Top, respectively. If you keep these differences in mind, you can see that Listing 2.2 defines the same four rectangles as the Silverlight/XAML code in Listing 2.1. Navigate to the location of Checkerboard1.svg and double-click on it, after which you will see a checkerboard pattern. Note that if you are using Internet Explorer, you can download Adobe’s SVG viewer at http://www.adobe.com/svg/viewer/install/main.html. After you have installed the SVG viewer, you will be able to render SVG code in Internet Explorer.
Rendering Rectangles with Opacity Figure 2.2 displays rectangles with an Opacity attribute. The Silverlight/XAML document OpacityRect1.xml in Listing 2.3 uses the Silverlight/XAML Rectangle object in order to render a set of rectangles with different Opacity values.
Rendering Rectangles with Opacity
Figure 2.2 Rectangles with different Opacity values.
Listing 2.3
OpacityRect1.xml
31
32
Chapter 2
n
Colors, Linear Gradients, and Radial Gradients
The Silverlight/XAML Rectangle object allows you to specify the opacity of an object via the Opacity attribute, which is a decimal number between 0 and 1, inclusive. The default value of the Opacity attribute is 1. Listing 2.3 renders a red rectangle and then a blue rectangle. Since the value of the Opacity attribute is less than 1, the overlapping rectangular region is a composite color. This composite color depends on the value of the Opacity attribute for each of the two rectangles. Now change the value of the Opacity attribute to 1 and verify that the overlapping rectangular region is a solid blue color. Notice how the perimeter of the first rectangle is rendered with a dashed pattern because of the following code snippet: StrokeDashArray="2 2"
The string "2 2" specifies a pattern of two pixels ‘‘on’’ and two pixels ‘‘off’’ for the perimeter of the rectangle. The perimeter of the second rectangle is also rendered with a dashed pattern via the following code snippet: StrokeDashArray="4 1 2 1"
The string "4 1 2 1" specifies a pattern of four pixels on, one pixel off, two pixels on, and one pixel off. Now that you understand how to render rectangles with an Opacity attribute and a StrokeDashArray attribute, you can understand the contents of Listing 2.4, which illustrates the SVG code that is equivalent to the Silverlight/XAML code in Listing 2.3. Listing 2.4
OpacityRect1.svg
Rendering a Cube in Silverlight/XAML
Rendering a Cube in Silverlight/XAML Figure 2.3 displays a cube via a Rectangle object and two Polygon objects.
Figure 2.3 A cube.
The Silverlight/XAML document Cube1.xml in Listing 2.5 demonstrates how to render a cube. Listing 2.5
Cube1.xml
33
34
Chapter 2
n
Colors, Linear Gradients, and Radial Gradients
Navigate to the location of Cube1.html and double-click on it so that you will be able to see a cube in a browser session. The cube consists of three objects: the toplevel yellow parallelogram, the red rectangular front face, and the right-side blue parallelogram. The top parallelogram is rendered via the following Polygon object:
The rectangular front face is rendered via the following Rectangle object:
The right-side parallelogram is rendered via the following Polygon object:
The equivalent SVG code for generating a cube also uses two SVG polygon elements and one SVG rect element, as illustrated in Listing 2.6. Listing 2.6
Cube1.svg
Rendering Rectangles with Linear Gradients
Navigate to the location of Cube1.svg and then double-click on it, and you will see a cube rendered in a browser.
Silverlight/XAML Color Gradients Silverlight/XAML provides two primary types of color gradients: linear gradients and radial gradients. These are defined via the LinearGradientBrush and RadialGradientBrush objects, respectively. Linear color gradients can be further subdivided into three types: horizontal linear gradients, vertical linear gradients, and diagonal linear gradients. Thus, Silverlight provides a rich variety of gradients that enable you to create visually stimulating effects. The next section provides examples of Silverlight/XAML code that contain linear gradients, after which you will learn how to write Silverlight/XAML code that contains radial gradients.
Silverlight/XAML Linear Gradients A linear gradient is defined in terms of two or more GradientStop objects, each of which contains a Color attribute and an Offset attribute. For example, if you define a linear gradient with an initial color of #FF0000 (red) and a final color of #000000 (black), then the resulting color gradient will range (in a linear fashion) from red to black. Linear gradients enable you to create vivid and interesting color combinations, and they are available in three varieties: horizontal, vertical, and diagonal. Note that linear gradient and linear color gradient are used interchangeably in this book.
Rendering Rectangles with Linear Gradients Figure 2.4 presents a rectangle with linear gradient shading. The Silverlight/XAML document Rect1LG1.xml in Listing 2.7 demonstrates how to draw overlapping rectangles with a linear gradient by means of the Silverlight/ XAML objects Rectangle and LinearGradientBrush.
35
36
Chapter 2
n
Colors, Linear Gradients, and Radial Gradients
Figure 2.4 A linear gradient rectangle.
Listing 2.7
Rect1LG1.xml
The Silverlight/XAML Rectangle object specifies a width of 300 pixels and height of 200 pixels. This rectangle contains a Rectangle.Fill object that contains a LinearGradientBrush object, which consists of three GradientStop objects.
Rendering Rectangles with Linear Gradients
The combination of the values for the StartPoint attribute and the EndPoint attribute determines whether the visual effect is a vertical linear gradient, a horizontal linear gradient, or a diagonal linear gradient. Listing 2.7 specifies the following combination of values:
Use the following combination of values to create a vertical linear gradient:
Use the following combination of values to create a diagonal linear gradient:
Experiment with different values for StartPoint and EndPoint to see how their values change the linear gradient. The equivalent SVG code is illustrated in Listing 2.8. Listing 2.8
Rect1LG1.svg
37
38
Chapter 2
n
Colors, Linear Gradients, and Radial Gradients
Radial Color Gradients A radial color gradient is the second type of built-in color gradient that is available in Silverlight/XAML. You can define a radial color gradient via the RadialGradientBrush object, which consists of two or more GradientStop objects. A radial color gradient can be compared to the ripple effect that is created when you drop a stone in a pond, where each ripple has a color that changes in a gradient fashion. Each ripple corresponds to a GradientStop object, with suitable values for the Color and Offset attributes. For example, if you define a radial gradient with a start color of #FF0000 (red) and an end color of #000000 (black), then the resultant color gradient will range—in a radial fashion—from red to black. Radial gradients can also contain multiple start/stop color combinations. The point to keep in mind is that radial gradients change colors in a linear fashion, but the rendered colors are drawn in an expanding radial fashion. Note that radial gradient and radial color gradient are used interchangeably in this book. Listing 2.9 displays the contents of Rect1RG1.xml, which demonstrates how to use the Silverlight/XAML RadialGradient object in order to define a radial color gradient that ranges radially from blue to red. Listing 2.9
Rect1RG1.xml
Rendering Parallelograms with Linear Gradients
Listing 2.9 contains a Silverlight/XAML Rectangle object with a radial gradient that ranges in a radial fashion from blue to red. Multiple GradientStop objects can be specified using standard colors, hexadecimal notation, or the (R,G,B) components of a color. Listing 2.10 displays the contents of the SVG document Rect1RG1.svg, which contains the SVG code that is the counterpart to the Silverlight/XAML code in Listing 2.8. Listing 2.10
Rect1RG1.svg
You can define a radial gradient with an id attribute that can then be referenced as the gradient definition for other Silverlight/XAML objects in the same Silverlight/ XAML document. The next example shows you how to specify this color definition for a parallelogram.
Rendering Parallelograms with Linear Gradients Listing 2.11 displays the contents of the Silverlight/XAML document PGram1LG1.xml, which demonstrates how to use the Silverlight/XAML Polygon object to render a parallelogram with a linear gradient.
39
40
Chapter 2
n
Listing 2.11
Colors, Linear Gradients, and Radial Gradients
PGram1LG1.xml
Listing 2.11 contains one parallelogram with a linear gradient. The following line defines the Points attribute that defines the four vertices of the parallelogram: Points="50,80 300,80 350,20 100,20"
This list of four vertices starts from the upper-left vertex and then specifies the coordinates of the other three vertices in a clockwise fashion. Note that you have the freedom to start from any vertex and list the remaining vertices of the polygon, either clockwise or counterclockwise. Choose a style that you prefer and try to be as consistent as possible; you’ll be surprised how much debugging time you will save by doing so. Listing 2.12 displays the content of the SVG document PGram1LG1.svg, which is the counterpart to the Silverlight/XAML code in Listing 2.11. Listing 2.12
PGram1LG1.svg
SpreadMethod, RadiusX, and RadiusY
SpreadMethod, RadiusX, and RadiusY Listing 2.13 displays the contents of the Silverlight/XAML document Rect1RGSpreadRadX1RadY1.xml, which renders four Silverlight/XAML Rectangle objects. Notice that each rectangle specifies a radial gradient with slightly different combinations of values for the attributes SpreadMethod, RadiusX, and RadiusY. Listing 2.13
Rect1RGSpreadRadX1RadY1.xml
41
42
Chapter 2
n
Colors, Linear Gradients, and Radial Gradients
SpreadMethod, RadiusX, and RadiusY
The relevant portions of the RadialGradientBrush objects for the rectangles in Listing 2.13 are reproduced here:
The Center attribute for the four rectangles are close to the pair 0.5 0.5. When the values for RadiusX and RadiusY are small (close to 0.1), you will see wave-like concentric circles or ellipses when the value of the SpreadMethod attribute is either Reflect or Repeat. The XAML code in the XAML document Rect1RGSpreadRadX1RadY1.xml does not have a direct counterpart in SVG. Linear gradients and radial gradients in SVG do have an fx attribute and an fy attribute, which correspond to the Center attribute in the RadialGradientBrush object in XAML. However, the RadiusX and RadiusY attributes in XAML are not defined in SVG.
43
44
Chapter 2
n
Colors, Linear Gradients, and Radial Gradients
Key Constructs A linear color gradient can be defined with the following code fragment:
A radial color gradient can be defined with the following code fragment:
Summary This chapter described how to define standard colors and various ways in which you can express colors in Silverlight/XAML. You also saw examples of linear color gradients and radial color gradients and how to combine these gradients with rectangles. The examples in this chapter showed you how to use the following Silverlight/XAML objects: n
The LinearGradient object for linear color gradients
n
The RadialGradient object for radial color gradients
n
The Polyline object for drawing rectangles
n
The Path object for drawing rectangles
chapter 3
Ellipses, Arcs, and Simple 3D Effects This chapter demonstrates how to use the Silverlight/XAML objects Ellipse and Path to render circles, ellipses, and elliptic arcs. The Silverlight/XAML Ellipse object allows you to specify circles as well as ellipses, whereas SVG provides both an SVG circle element and an SVG ellipse element. You will learn how these Silverlight/XAML objects can be combined with linear color gradients and radial color gradients to create richer graphics images. Unfortunately, rendering elliptic arcs in Silverlight/XAML (and SVG as well) is not nearly as straightforward or intuitive as in other languages such as Java. You may already know that Java uses intuitive drawArc and fillArc methods for rendering elliptic arcs, whereas Silverlight/XAML uses a Path object to render elliptic arcs. On the other hand, the Silverlight/XAML Path object is a highly versatile construct that can be used for rendering Be´zier curves in addition to elliptic arcs. This chapter contains examples that will give you an understanding of the versatility of the Silverlight/XAML Path object. This chapter also shows you techniques for defining radial color gradients for creating three-dimensional effects. These techniques are based on the manner in which you specify the stop-color/offset combinations. In particular, you’ll see radial color gradients combined with circles to create pseudo spheres.
45
46
Chapter 3
n
Ellipses, Arcs, and Simple 3D Effects
The Silverlight/XAML Ellipse Object Figure 3.1 displays an ellipse and a circle via two Ellipse objects. In mathematics, you can uniquely identify a circle by specifying its center point and its radius, whereas an ellipse is uniquely determined by specifying its center as well as its major and minor axes. Sometimes you will also see an ellipse referred to as an oval. A bounding rectangle is the smallest rectangle that encloses an ellipse (or a circle). Alternatively, the width, height, and upper-left vertex of a bounding rectangle can be used to specify an ellipse (or a circle), as demonstrated in this example. The Silverlight/XAML document Ovals1.xml in Listing 3.1 uses the Ellipse object to render a circle and an ellipse. Listing 3.1
Ovals1.xml
Listing 3.1 contains two Ellipse objects that are defined in terms of their bounding rectangles. The coordinates of the upper-left vertex of the bounding rectangle of the first Ellipse object are (100,100). The width and height of this same rectangle are 100 and 100, respectively. The width of the rectangle (parallel to the horizontal axis) is twice the major axis; therefore, the major axis is 50 (100 divided by 2). The height of the bounding rectangle (parallel to the vertical axis) is twice the minor axis; therefore, the minor axis is also 50 (100 divided by 2). Thus, the center of the Ellipse object has the coordinates (100,100) + (50,50) = (150,150). The coordinates of the upper-left vertex of the bounding rectangle of the second Ellipse object in Listing 3.1 are (250,100). The width and height of this same rectangle are 200 and 100, respectively. Thus, the major axis is 100 (200 divided by 2), and the minor axis is 50 (100 divided by 2). The center of the second Ellipse object has the coordinates (250,100) + (100,50) = (350,150).
The Silverlight/XAML Ellipse Object
Figure 3.1 A circle and an ellipse.
You can think of Ellipse objects in terms of their bounding rectangles or in terms of their center and their major and minor axes. Silverlight/XAML Ellipse objects use the former style, whereas SVG ellipse elements use the latter style. You can use whichever style you prefer, but it’s a good idea to become comfortable with both techniques. You can also use the EllipseGeometry object to define an ellipse. For example, the second Ellipse object in Listing 3.1 can be defined via an EllipseGeometry object, as shown in the code fragment here:
Listing 3.2 displays the contents of the document Ovals1.svg, which corresponds to the Silverlight/XAML document Ovals1.xml. Listing 3.2
Ovals1.svg
Rendering Ellipses with Linear Gradients Figure 3.2 depicts an ellipse with linear gradient shading. The Silverlight/XAML document Ellipse1LG1.xml in Listing 3.3 renders two ellipses with linear gradient shading. Listing 3.3
Ellipse1LG1.xml
The Silverlight/XAML code in Listing 3.3 renders one ellipse with linear gradient shading. The linear gradient has an initial color of yellow that is specified by the first stop color and a final color of black that is specified in the third stop color. The intermediate colors vary from yellow to black, and their R,G,B values are calculated by means of a linear gradient to achieve the effect that you see in Figure 3.2.
Rendering Ellipses with Linear Gradients
Figure 3.2 An ellipse with a linear gradient.
Listing 3.4 displays the contents of the document Ellipse1LG1.svg, which corresponds to the Silverlight/XAML document Ellipse1LG1.xml. Listing 3.4
Ellipse1LG1.svg
49
50
Chapter 3
n
Ellipses, Arcs, and Simple 3D Effects
Rendering Ellipses with Radial Gradients Figure 3.3 depicts an ellipse with radial gradient shading. The Silverlight/XAML document Ellipse1RG1.xml in Listing 3.5 renders a single ellipse with radial gradient shading. Listing 3.5
Ellipse1RG1.xml
Figure 3.3 An ellipse with a radial gradient.
Rendering Ellipses with Radial Gradients
The Silverlight/XAML code in Listing 3.5 renders one ellipse with radial gradient shading. The radial gradient has an initial color of yellow, an intermediate color of red, and a terminal color of blue. Unlike linear gradients, the intermediate colors are calculated by means of a radial gradient in order to achieve the effect that you see in Figure 3.3. To understand how the intermediate colors are determined, imagine the effect of dropping a stone into a pond and capturing the set of concentric circles. The colors of these circles are based on the set of colors that you obtain by a color gradient that starts at yellow and ends with blue. Here’s an interesting point about radial color gradients: If you drew a line segment with one end-point coinciding with the center of all the concentric circles, that line segment would be colored with a linear gradient. One more point about the second ellipse in this example: Notice how the values for the stroke-dasharray attribute and the stroke attribute create a slightly polished effect on the circumference of the ellipse. SVG does not have a direct equivalent to the Silverlight/XAML code; creating this effect requires explicitly defining a radial gradient. Listing 3.6 displays the contents of the document Ellipse1RG1.svg, which corresponds to the Silverlight/ XAML document Ellipse1RG1.xml. Listing 3.6
Ellipse1RG1.svg
51
52
Chapter 3
n
Ellipses, Arcs, and Simple 3D Effects
Creating Elliptic Arcs with Path Figure 3.4 displays elliptic arcs that are rendered via the Path object. In a language such as Java, you define a circular or an elliptic arc in terms of its width, height, start angle, end angle, and the coordinates of the upper-left vertex of the smallest rectangle that bounds the circle or the ellipse. On the other hand, Silverlight/XAML requires that you specify a start point and an end point and then whether you want to render a major or a minor arc, either clockwise or counterclockwise. The Silverlight/XAML document EllipticArc1.xml in Listing 3.7 illustrates how to define elliptic arcs via the Path object. Listing 3.7 displays the SVG document EllipticArc1.svg, which corresponds to the XAML code in Listing 3.7. Listing 3.7
EllipticArc1.xml
Figure 3.4 Elliptic arcs and the Path object.
Creating Elliptic Arcs with Path
The Fill color of the elliptic arc is Red, the Stroke value is Black, and the StrokeThickness is 4. The first portion of the Path object consists of the following:
Listing 4.14 defines a cubic Be´zier curve, followed by a quadratic Be´zier curve, both of which are defined inside a BezierSegment object. The cubic Be´zier curve is defined via the following code fragment:
The StartPoint attribute specifies the initial point, and the Point3 attribute specifies the final point. The Point1 attribute and the Point2 attribute specify the two control points for this cubic Be´zier curve. Thus, the preceding cubic Be´zier curve is equivalent to the following Data attribute of a Path object: Data="M 0,50 C 400,200 200,-150 100,350"
The quadratic Be´zier curve in Listing 4.8 is defined via the following code fragment:
The StartPoint attribute specifies the initial point, and the Point2 attribute specifies the final point. The Point1 attribute specifies the single control point for this quadratic Be´zier curve. Thus, the preceding quadratic Be´zier curve is equivalent to the following Data attribute of a Path object: Data="M 20,20 C 250,50 100,100"
Silverlight also provides a QuadraticBezierSegment that you can use instead of a BezierSegment to define a quadratic Be´zier curve, as shown here:
You can use PolyQuadraticBezierSegment in order to connect multiple quadratic Be´zier curves. For example, the following code fragment connects two quadratic Be´zier curves:
89
90
Chapter 4
n
Be´zier Curves and Color Gradients
The preceding code snippet connects the quadratic Be´zier curves defined by the following Data attributes for a pair of Path objects: Data="20,20 250,50 100,100" Data="100,00 80,250 150,-20"
Alternatively, you can use the PolyBezierSegment in order to connect multiple Be´zier curves. For example, the following code fragment connects the same quadratic Be´zier curves that are defined in the preceding PolyQuadraticBezierSegment: Point X="250" Y=50"/> Point X="100" Y="100"/> Point X="80" Y="250"/> Point X="150" Y="-20"/>
The preceding PolyBezierSegment object defines two connected quadratic Be´zier curves that are defined by the following Data attributes for a pair of Path objects: Data="20,20 250,50 100,100" Data="100,00 80,250 150,-20"
SVG does not provide a direct counterpart to BezierSegment objects.
Using the GeometryGroup Object The GeometryGroup object is useful when you need to treat multiple objects as a single logical group. Figure 4.10 displays three objects that are defined inside a GeometryGroup object. Listing 4.15 displays the contents of the Silverlight/XAML document GeometryGroup1.xml, which demonstrates how to define a cubic Be´zier curve, a rectangle, and an ellipse inside a GeometryGroup object. Listing 4.15
GeometryGroup1.xml
Using the GeometryGroup Object
Figure 4.10 A Be´zier curve, a rectangle, and an ellipse in a GeometryGroup object.
91
92
Chapter 4
n
Be´zier Curves and Color Gradients
The GeometryGroup object starts with a Be´zier curve, as shown here:
The StartPoint attribute specifies the initial point of the cubic Be´zier curve. The Point1 attribute specifies the first control point; the Point2 attribute specifies the second control point; the Point3 attribute specifies the terminal point of the cubic Be´zier curve. The equivalent Data attribute for this cubic Be´zier curve is shown here: Data="M400,200 C400,200 200,-150 100,350"
Next, the GeometryGroup object specifies a rectangle via the RectangleGeometry object, as shown here:
The first pair of numbers specifies the upper-left corner of the rectangle; in this case, that corner has coordinates 200,100. The third number specifies the width of the rectangle, and the fourth number specifies the height of the rectangle. In this case, the width and height are 150 and 50, respectively. Finally, the GeometryGroup object specifies an ellipse via the EllipseGeometry object, as shown here:
You can refer to the discussion following Listing 4.12 to get additional information about the EllipseGeometry object. Recall that you can also place multiple objects inside a Canvas object (that is also a child element of the root Canvas object) to treat them as a single logical group. SVG does not provide a direct counterpart to GeometryGroup objects.
Key Constructs
Key Constructs A quadratic Be´zier curve can be defined with the following Path object:
A cubic Be´zier curve can be defined with the following Path object:
A double cubic Be´zier curve can be defined with the following Path object:
A reflected cubic Be´zier curve can be defined with the following Path object:
A cubic Be´zier curve can be defined with the following Path object with an embedded BezierSegment object:
93
94
Chapter 4
n
Be´zier Curves and Color Gradients
A cubic Be´zier curve can be defined with the following Path object that contains an embedded GeometryGroup object, which in turn contains an embedded BezierSegment object:
Summary This chapter focused on how you can create very pleasing curvilinear graphics images that are based on quadratic Be´zier curves and cubic Be´zier curves. In particular, you saw Silverlight/XAML examples of the following: n
The Path object for rendering a quadratic Be´zier curve
n
The Path object for rendering a cubic Be´zier curve
n
The Path object for rendering multiple Be´zier curves
n
The Path object for rendering multiple Be´zier curves
n
The BezierSegment object for rendering multiple Be´zier curves
n
The GeometryGroup object for rendering multiple unrelated objects and multiple Be´zier curves
chapter 5
Silverlight/XAML Transformations This chapter demonstrates how to specify transformations in Silverlight/XAML documents with TranslateTransform, ScaleTransform, RotateTransform, and SkewTransform. Although you have already seen some examples of transformations in previous chapters, this chapter consolidates the description of these transformations, and you’ll see how to use them with rectangles and ellipses to perform manipulations on a variety of graphics images. These Silverlight/XAML transformations provide sophisticated geometric manipulations that can greatly enhance the visual appeal of your graphics images. For instance, you can use TranslateTransform to shift the contents of a Canvas object anywhere in the plane. This functionality makes for cleaner Silverlight/XAML code because you can avoid using hard-coded values to specify the location of individual XAML objects. For example, you can define a rectangle whose upperleft vertex is the origin 0,0 and then use TranslateTransform to render multiple copies of that rectangle on the screen. This functionality is extremely useful when you need to render business charts that can be decomposed into many logical components. ScaleTransform makes it very easy to resize the graphics image rendered inside a Canvas object. While this functionality is much more difficult to achieve in
imperative programming languages, Silverlight/XAML makes transformationbased functionality available through a very simple code fragment. You can also combine TranslateTransform and ScaleTransform, which enables you to render 95
96
Chapter 5
n
Silverlight/XAML Transformations
many scaled copies of a graphics image. Keep in mind that there is no practical limit to the complexity of the graphics image defined in a Canvas object; consequently, you can easily create a visually rich collage based on a single graphics image. RotateTransform allows you to rotate a graphics image that is defined in a Silverlight/XAML Canvas object with a very simple code fragment. SVG provides skewX and skewY, whereas XAML provides just SkewTransform. You also need to specify AngleX or AngleY (or both) to create a skewing effect on the horizontal axis or the vertical axis. is the most sophisticated of the Silverlight/XAML transformations. This transformation allows you to perform a linear transformation on the contents of a Canvas object, and it can be specified by a very simple code fragment. If you do not have a solid understanding of the mathematics of linear transformations, it might be easier to find an equivalent set of transformations based on other Silverlight/XAML transformations instead of using MatrixTransform. MatrixTransform
When you’ve finished this chapter, you will have an understanding of the tremendous number of ways to combine Silverlight/XAML transformations. They also can be easily combined with color gradients to create graphics images that are impossible to achieve with a comparable amount of effort in traditional programming languages.
TranslateTransform Transformation Consider the translated rectangles rendered in Figure 5.1. The Silverlight/XAML document Rect1Translate1.xml in Listing 5.1 demonstrates how to use TranslateTransform to translate or shift a set of rectangles. Listing 5.1
Rect1Translate.xml
TranslateTransform Transformation
Figure 5.1 Rendering rectangles with TranslateTransform.
The code in Listing 5.1 defines two Rectangle objects in a Canvas object. The TranslateTransform object is applied to the second Rectangle object, which shifts the upper-left corner of the second rectangle. The new coordinates are (100,10) þ (50,50) = (150,60) because (100,10) is the initial upper-left vertex, and (50,50) is the shift due to the TranslateTransform contained in the second Rectangle object. Although TranslateTransform is simple, it can be useful for shifting individual Silverlight/XAML objects that are contained in a Canvas object. Note that when you need to move a group of objects that are contained in a Canvas object, you can specify values for the attributes Canvas.Left and Canvas.Top. Later in this chapter you will see how you can combine TranslateTransform with other transformations.
97
98
Chapter 5
n
Silverlight/XAML Transformations
Listing 5.2 displays the contents of Rect1Translate1.svg, which contains the SVG code that corresponds to the Silverlight/XAML code in Rect1Translate1.xml. Listing 5.2
Rect1Translate1.svg
RotateTransform Transformation Consider the two rotated rectangles in Figure 5.2. The Silverlight/XAML document Rect1Rotate1.xml in Listing 5.3 demonstrates how to use RotateTransform to rotate a pair of rectangles. Listing 5.3
Rect1Rotate1.xml
RotateTransform Transformation
Figure 5.2 Rotated rectangles via RotateTransform.
99
100
Chapter 5
n
Silverlight/XAML Transformations
Listing 5.3 contains Silverlight/XAML code for three rotated rectangles. The rotation effect for the first rectangle is specified by the code fragment that is reproduced here:
RotateTransform contains the Angle attribute that specifies the clockwise angle of
rotation, with the positive (right-side) horizontal axis as the starting place for the rotation. In this example, the angle of rotation is 308. The angle of rotation for the second and third rectangles is 758 and 458, respectively. You can confirm this is true by noting that the red Rectangle object has been rotated (keeping the upper-left vertex fixed) clockwise by 308. The blue Rectangle object has been rotated clockwise by 458, and the yellow Rectangle object has been rotated clockwise by 758. Keep in mind that, in mathematics (and for some programming languages), clockwise rotations are negative and counterclockwise rotations are positive, which is the opposite of Silverlight objects. Listing 5.4 displays the contents of Rect1Rotate1.svg, which lists the SVG code that corresponds to Silverlight/XAML code in Rect1Rotate1.xml. Listing 5.4
Rect1Rotate1.svg
ScaleTransform Transformation
ScaleTransform Transformation Consider the scaled rectangles in Figure 5.3.
Figure 5.3 Scaled rectangles via ScaleTransform.
The Silverlight/XAML document Rect1Scaled1.xml in Listing 5.5 demonstrates how to use ScaleTransform to scale three rectangles. Listing 5.5
Rect1Scaled1.xml
Listing 5.5 contains three scaled rectangles. The scaling effect for the first rectangle is specified by the following code fragment:
ScaleTransform contains the ScaleX attribute that specifies the horizontal scaling factor and the ScaleY attribute that specifies the vertical scaling factor. In this example, both attributes have the value 2.5, which means that the width and the height of the rectangle are scaled by a factor of 2.5. Note that the value of the ScaleX attribute is independent of the value of the ScaleY attribute.
Instead of using a ScaleTransform, you can also define Rectangle objects with larger Width and Height attributes. Since the two techniques produce the same results, use the technique that is most convenient for you. Listing 5.6 displays the contents of Rect1Scaled1.svg, which lists the SVG code that corresponds to Silverlight/XAML code in Rect1Scaled1.xml. As you have seen in previous examples, the syntax for specifying transformations in SVG differs from the syntax in Silverlight/XAML. For example, the following SVG code snippet:
corresponds to the following XAML code snippet:
Multiscaled Cubic Be´zier Curves
Note that scaled elements in SVG and scaled objects in XAML exhibit different behavior when they are rendered: SVG shifts the upper-left vertex of the rectangles, whereas Silverlight does not perform such a shift. Listing 5.6
Rect1Scaled1.svg
Multiscaled Cubic Be´zier Curves You can apply multiple transformations to a geometric object by including those transformations inside a TransformGroup object. For example, consider the set of scaled cubic Be´zier curves in Figure 5.4. The Silverlight/XAML document MultiScaledCBezier1.xml in Listing 5.7 demonstrates how to render a set of scaled cubic Be´zier curves to create an abstract effect. Listing 5.7
MultiScaledCBezier1.xml
Multiscaled Cubic Be´zier Curves
Figure 5.4 A set of scaled cubic Be´zier curves.
The code in Listing 5.7 contains four Path objects, each of which contains the TransformGroup object inside a Path.RenderTransform to specify a set of transformations. Each TransformGroup object consists of a ScaleTransform, a SkewTransform, and a TranslateTransform. Since all four Path objects render a scaled version of the same cubic Be´zier function, we’ll examine only the first one in detail. The first Path object specifies a red cubic Be´zier curve whose blue dotted outline has a width of 4 because of the following code fragment: StrokeDashArray="1 1" Stroke="Black" StrokeThickness="4"
The cubic Be´zier curve itself is specified by the following line of code: Data="M0,0 C75,150 150,10 10,80"
105
106
Chapter 5
n
Silverlight/XAML Transformations
The start point of the Be´zier curve is the point 0,0 because of the term M0,0, and the terminal point of the Be´zier curve is the point 10,80, which is listed at the end of the code fragment. Next, the fragment C75,150 150,10 specifies two control points, 75,150 and 150,10, which are used for rendering the cubic Be´zier curve. The control point 75,150 is used for drawing the beginning of the Be´zier curve, and the control point 150,10 is used for drawing the end of Be´zier curve. Note that the uppercase letters M and C in a cubic Be´zier curve refer to absolute points, whereas the lowercase letters m and c refer to relative points. Listing 5.8 displays the contents of MultiScaledCBezier1.svg, which corresponds to the Silverlight/XAML code in MultiScaledCBezier1.xml. Note that the SVG elements are rendered differently from the Silverlight/XAML objects. Listing 5.8
MultiScaledCBezier1.svg
SkewTransform Transformation Consider the skewed rectangles in Figure 5.5.
Figure 5.5 Drawing rectangles with SkewTransform.
The Silverlight/XAML document RectSkewed1.xml in Listing 5.9 demonstrates how to use SkewTransform to render a set of skewed rectangles. Listing 5.9
Rect1Skewed1.xml
107
108
Chapter 5
n
Silverlight/XAML Transformations
The Silverlight/XAML code in Listing 5.9 consists of three skewed rectangles. The first Rectangle object contains a Rectangle.RenderTransform that contains a SkewTransform, which in turn contains an AngleX attribute whose value is 30. The AngleX attribute specifies a skewing with respect to the horizontal axis. The skew is accomplished by keeping the horizontal axis fixed while rotating the vertical axis counter clockwise by the specified number of degrees, which in this case is 30. Similarly, the second Rectangle object contains a SkewTransform whose AngleX attribute is 75. By contrast, the third Rectangle object contains a SkewTransform with an AngleY attribute, which specifies a skewing with respect to the vertical axis. This skew is performed by keeping the vertical axis fixed and rotating the horizontal axis clockwise by the specified number of degrees, which in this case is 75.
MatrixTransform Transformation
Notice how the third rectangle appears longer than the first rectangle, which shows that SkewTransform actually performs two things: a rotation and a scale of a geometric object. Listing 5.10 displays the contents of Rect1Skewed1.svg, which lists the SVG code that corresponds to the Silverlight/XAML code in Rect1Skewed1.xml. Listing 5.10
Rect1Skewed1.svg
MatrixTransform Transformation Consider the rectangles in Figure 5.6. The Silverlight/XAML document Rect1Matrix1.xml in Listing 5.11 demonstrates how to use MatrixTransform to perform linear transformations on a rectangle in the plane. Listing 5.11
Rect1Matrix1.xml
109
110
Chapter 5
n
Silverlight/XAML Transformations
The Silverlight/XAML code in Listing 5.11 renders three rectangles, each of which has a width of 200 and height of 100. The rectangles are red, blue, and orange, and their perimeters are blue, red, and black, respectively. The first rectangle is rendered with a Rectangle object that contains no transformations.
MatrixTransform Transformation
Figure 5.6 Drawing rectangles with MatrixTransform.
The second Rectangle object contains a MatrixTransform, which is reproduced here:
MatrixTransform specified in the Silverlight/XAML code for the second rectangle
represents a clockwise rotation of 308 of the associated rectangle. The mathematics for rotations is beyond the scope of this book. If you are interested in the details, the topic is covered in books on linear algebra. The third rectangle is rendered with the following code fragment:
111
112
Chapter 5
n
Silverlight/XAML Transformations
MatrixTransform,
specified in the code for the third rectangle, represents a combination of a skew and a rotation. Again, the mathematics that provide the details can be found in a book on linear algebra. One more thing to remember is that if any of the terms M11, M12, M21, or M22 is 0, you can safely omit the zerovalued terms, which makes your code slightly more compact. Listing 5.12 displays the contents of the SVG document Rect1Matrix1.svg, which contains SVG code that is similar to the Silverlight/XAML document Rect1Matrix1.xml. Listing 5.12
Rect1Matrix1.svg
Cylinders and ScaleTransform Transformation Figure 5.7 shows two horizontal cylinders, and the second cylinder is a scaled version of the first cylinder. The XAML document HScaledLGradientCylinder1.xml in Listing 5.13 demonstrates how to use ScaleTransform to render a cylinder and a scaled cylinder. Listing 5.13
HScaledLGradientCylinder1.xml
Cylinders and ScaleTransform Transformation
113
114
Chapter 5
n
Silverlight/XAML Transformations
Figure 5.7 Drawing scaled cylinders with ScaleTransform.
The Silverlight/XAML code in Listing 5.13 consists of an outer Canvas object that contains two Canvas objects, each of which renders a cylinder with gradient shading. The first Canvas object renders a cylinder by rendering the leftmost
Cylinders and ScaleTransform Transformation
ellipse, a rectangle, and then the rightmost ellipse. The front of the cylinder is a rectangle, which is rendered with a linear gradient. The second Canvas object contains a ScaleTransform in order to render another cylinder that is a scaled version of the first cylinder. The second Canvas object encloses the first Canvas object with the following code:
Note that instead of enclosing multiple Silverlight/XAML objects in a single Canvas object, you can also enclose individual Silverlight/XAML objects with a Canvas object. For example, the following code snippet illustrates how you can enclose a single Ellipse object in a Canvas object that also specifies a Canvas.RenderTransform:
Keep in mind that specifying multiple Canvas.RenderTransform objects can also require more effort in terms of code maintenance. Regardless of the technique you use in your code, ScaleTransform makes it very easy to generate any number of scaled versions of an existing graphic image. Listing 5.14 displays the contents of HScaledLGradientCylinder1.svg, the SVG document that corresponds to the Silverlight/XAML document HScaledLGradientCylinder1.xml .
115
116
Chapter 5
n
Listing 5.14
Silverlight/XAML Transformations
HScaledLGradientCylinder1.svg
Hourglass: ScaleTransform and SkewTransform
Hourglass: ScaleTransform and SkewTransform Figure 5.8 shows two hourglass figures using scaling and skewing transformations.
Figure 5.8 Drawing scaled and skewed hourglass figures.
117
118
Chapter 5
n
Silverlight/XAML Transformations
The XAML document VScaledSkewedGradientHourGlass1.xml in Listing 5.15 demonstrates how to combine ScaleTransform and SkewTransform to render skewed hourglass figures. Listing 5.15
VScaledSkewedGradientHourGlass1.xml
Hourglass: ScaleTransform and SkewTransform
119
120
Chapter 5
n
Silverlight/XAML Transformations
Hourglass: ScaleTransform and SkewTransform
Listing 5.15 consists of two Canvas objects, each of which renders an hourglass figure with gradient shading. The first Canvas object displays an hourglass by rendering the top ellipse and a triangle with linear gradient shading and then another ellipse that creates the blue circumference. This combination of components is reflected to create the lower half of the hourglass figure. The first Canvas object specifies a TransformGroup that contains TranslateTransform and SkewTransform, as shown here:
The second Canvas object specifies a TransformGroup that contains a ScaleTransform and SkewTransform to render a scaled and skewed hourglass figure that is derived from the first hourglass figure. The larger hourglass figure in the first Canvas object uses TranslateTransform, ScaleTransform, and SkewTransform, as shown here:
Listing 5.16 displays VScaledSkewedGradientHourGlass1.svg, which corresponds to the Silverlight/XAML document ScaledSkewedGradientHourGlass1.xml. Listing 5.16
VScaledSkewedGradientHourGlass1.svg
Transformations of Text Strings
Transformations of Text Strings Figure 5.9 displays text strings that have undergone various transformations. The XAML document TransformedText1.xml in Listing 5.17 demonstrates how to scale, rotate, and skew various text strings.
Figure 5.9 Applying transformations to text strings.
123
124
Chapter 5
n
Listing 5.17
Silverlight/XAML Transformations
TransformedText1.xml
Transformations of Text Strings
Listing 5.17 displays five text strings, each of which has a different set of attribute values. The first text string sets the value of the TextWrapping attribute to Wrap, which means that the text will be rendered on multiple lines:
The second text string is rendered with the Arial font because it specifies the FontFamily attribute, as shown here:
The third text string is rotated by 308 because the TextBlock.RenderTransform object contains a RotateTransform transformation, as shown here:
The fourth text string is scaled because TextBlock.RenderTransform contains a ScaleTransform transformation, as shown here:
125
126
Chapter 5
n
Silverlight/XAML Transformations
The fifth text string is skewed because TextBlock.RenderTransform contains a SkewTransform transformation, as shown here:
Key Constructs A TranslateTransform transformation can be applied to a Rectangle object with the following code:
A RotateTransform transformation can be applied to a Rectangle object with the following code:
A ScaleTransform transformation can be applied to a Rectangle object with the following code:
A SkewTransform transformation can be applied to a Rectangle object with the following code:
Summary
Summary This chapter showed you how to apply Silverlight/XAML transformations to XAML objects, such as ellipses, rectangles, and text strings. Although these effects usually require considerable effort in traditional programming languages, Silverlight/XAML enables you to create these effects declaratively with a few lines of code. The first part of the chapter showed how to apply individual Silverlight/ XAML transformations to an object. The second part of the chapter showed examples of combining multiple Silverlight/XAML transformations and applying the aggregated transformation to an object. Silverlight/XAML supports the following transformations that can be applied to Silverlight/XAML objects: n
The TranslateTransform transformation
n
The RotateTransform transformation
n
The ScaleTransform transformation
n
The SkewTransform transformation
n
The MatrixTransform transformation
127
This page intentionally left blank
chapter 6
Silverlight and the DOM
This chapter contains examples of HTML files with JavaScript functions that enable you to access XAML objects in the Silverlight/XAML DOM (Document Object Model). For example, you will learn how to use the FindName function for locating existing XAML objects so that you can modify the values of their attributes. The second part of this chapter contains examples of defining inline XAML and rendering checkerboard patterns with color gradients. You will also see an example of adding a mouse event listener to an HTML button so that you can update the attributes of a Silverlight/XAML Rectangle object that is defined in an XML document. Thus, you will see the code for handling a variety of situations that involve the dynamic detection of existing objects and the dynamic creation of new objects. The DOM is the internal structure that enables us to manipulate the existing Silverlight/XAML objects that are defined in the associated XML document, as well as dynamically add new Silverlight/XAML objects. This chapter provides a rudimentary discussion of the DOM; however, you can find numerous DOMrelated articles on the Internet that are devoted to explaining it in greater detail.
XAML FindName in JavaScript The FindName function allows you to find named objects. Listing 6.1 defines a blue rectangle whose Name attribute has the value MyRect1. The code in Listing 6.2 illustrates how to find this rectangle programmatically and then change its color 129
130
Chapter 6
n
Silverlight and the DOM
from blue to red. Since the color of the rectangle is changed before the rectangle is rendered, you will never see the original blue rectangle. Listing 6.1
RectFindName1.xml
Listing 6.2
RectFindName1.html
Silverlight Graphics var rectNode = null; function onLoad(control, context, rootElement) { rectNode = control.Content.FindName("MyRect1"); rectNode.Fill = "Red"; } createSilverlight();
Navigate to the location of the HTML file RectFindName1.html and double-click on it to launch it in a browser session. Notice that the rectangle is red, despite the
XAML FindName in JavaScript
fact that its Fill attribute is Blue in RectFindName1.xml. If you are not sure why this happened, read the following discussion. Listing 6.2 starts with standard HTML code, followed by references to two JavaScript files that are needed for this HTML file:
The first JavaScript file is the standard Silverlight.js file, and the second is CreateSilverlightFindRectdName1.js, which contains a function that invokes the appropriate JavaScript code in Silverlight.js. Both files are located in the js subdirectory. Notice that the HTML file FindRectName1.html contains a JavaScript function called onLoad; this function is executed immediately after the HTML file FindRectName1.html is loaded into a browser session and before anything is rendered in the browser. The next portion of Listing 6.2 contains the definition of the onLoad JavaScript function: function onLoad(control, context, rootElement) { rectNode = control.Content.FindName("MyRect1"); rectNode.Fill = "Red"; }
The onLoad function is executed when the HTML file RectFindName1.html is launched in a browser session. This function does two things. First, it locates a XAML object whose name is MyRect1, which (in this example) is the name of a Rectangle object that is defined in the Silverlight/XAML document FindRectName1.xml that is located in the xaml subdirectory. Note that the FindName function finds this Rectangle object in the DOM that was created dynamically after you launched the HTML file RectFindName1.html. The second thing the onLoad function does is set the Fill attribute of the Rectangle object to Red. You can also change other attributes of the current rectangle just as easily as the Fill attribute. For example, you can set the StrokeWidth attribute to 8 with this code: rectNode.StrokeWidth = "8";
131
132
Chapter 6
n
Silverlight and the DOM
Add new objects to RectFindName1.xml and then modify the code in RectFindName1.html that will update various attributes of those new objects. Experiment with the code until you are comfortable with this type of modification to the HTML code. The last part of Listing 6.2 invokes the standard Silverlight object creation code: createSilverlight();
This simple example illustrates the ease with which you can locate objects in a Silverlight/XAML document and then update their attributes. Moreover, you can use your existing knowledge of JavaScript to write sophisticated Silverlight/ XAML applications.
Defining In-Line XAML via JavaScript Figure 6.1 displays a rectangle that is created dynamically in JavaScript code. The HTML file InlineRect1.html in Listing 6.3 illustrates how to use in-line code to create a Rectangle object dynamically and then add it to the Canvas object that is defined in EmptyCanvas1.xml.
Figure 6.1 Adding an in-line Rectangle object via JavaScript.
Defining In-Line XAML via JavaScript
Listing 6.3
InlineRect1.html
Silverlight Graphics var rectWidth var rectHeight var RLG1 var rect var rectNode
= = = = =
300; 300; ""; ""; null;
// red linear gradient... RLG1 + = ’’; RLG1 + = ’ ’; RLG1 + = ’ ’; RLG1 + = ’ ’; RLG1 + = ’ ’; RLG1 + = ’’; function onLoad(control, context, rootElement) { rect + = ’’; rect + = RLG1; rect + = ’’; rectNode = control.Content.CreateFromXaml(rect); rootElement.Children.Add(rectNode); }
133
134
Chapter 6
n
Silverlight and the DOM
createSilverlight();
Listing 6.3 starts with some standard HTML code, followed by a reference to two JavaScript functions:
The next section of Listing 6.3 contains a set of global variables: var var var var var
rectWidth rectHeight RLG1 rect rectNode
= 300; = 300; = ""; = ""; = null;
It’s convenient (but not necessary) to define all these variables globally and place them in one location so that you can get a better sense of the purpose of the variables and the context in which they will be used. If you want to be even more explicit, you can add comments as well: var var var var var
rectWidth rectHeight RLG1 rect rectNode
= 300; // the rectangle width = 300; // the rectangle height = ""; // a Red Linear Gradient = ""; // a rectangle string = null; // a Rectangle object
The interesting part of the code in Listing 6.3 starts with the definition of the variable RLG1, which represents a linear gradient color. The value of RLG1 is dynamically constructed by concatenating a set of strings to create a syntactically correct XML fragment: RLG1 RLG1 RLG1 RLG1 RLG1 RLG1 RLG1
= += += += += += +=
’’; ’ ’; ’ ’; ’ ’; ’ ’; ’’;
Dynamic Creation of XAML Objects
Next, the onLoad function is defined, and it requires three variables: function onLoad(control, context, rootElement)
These variables are provided automatically by Silverlight; i.e., you do not need to define them in the HTML file. The rect variable represents a Rectangle object, and its value is also constructed dynamically: rect rect rect rect rect
= ’’; + = RLG1; + = ’’;
Notice how single quotes are used to concatenate strings that have embedded double quotes. At this point the rect variable is simply a string that contains the code for a Rectangle object. The creation of a bona fide Rectangle object takes place via this code: rectNode = control.Content.CreateFromXaml(rect);
The rectNode variable is a reference to an actual Rectangle object that exists in memory; however, this Rectangle object is not yet visible in your browser. The last line of code appends this Rectangle object to the existing DOM: rootElement.Children.Add(rectNode);
The JavaScript code in Listing 6.3 captures the essence of creating Silverlight/ XAML objects dynamically and then appending those objects to the current DOM. The last part of Listing 6.3 invokes the standard Silverlight object creation code: createSilverlight();
Dynamic Creation of XAML Objects Figure 6.2 displays a dynamically created Ellipse object.
135
136
Chapter 6
n
Silverlight and the DOM
Figure 6.2 Dynamically creating an ellipse in JavaScript.
Listing 6.4 displays the contents of the HTML file DynamicEl1ipse1.html, which contains the JavaScript code for dynamically creating an ellipse and then adding that ellipse to the Canvas object in DynamicEllipse1.xml. Listing 6.4
DynamicEllipse1.html
Silverlight Graphics // ’onLoad’ function... function onLoad(control, context, rootElement) { var myEllipse = control.Content.CreateFromXaml(""); myEllipse.Fill myEllipse.Width myEllipse.Height
= "Blue"; = 200; = 100;
Dynamic Creation of XAML Objects myEllipse.Stroke = "Red"; myEllipse.StrokeThickness = "4"; myEllipse["Canvas.Top"] myEllipse["Canvas.Left"]
= 50; = 50;
rootElement.Children.Add(myEllipse); } createSilverlight();
Listing 6.4 shows a second technique for creating Silverlight/XAML objects that is different from the in-line technique in Listing 6.3. After the usual initialization code, Listing 6.4 defines an onLoad function: function onLoad(control, context, rootElement) { var myEllipse = control.Content.CreateFromXaml(""); myEllipse.Fill = "Blue"; myEllipse.Width = 200; myEllipse.Height = 100; myEllipse.Stroke = "Red"; myEllipse.StrokeThickness = "4"; myEllipse["Canvas.Top"] = 50; myEllipse["Canvas.Left"] = 50; rootElement.Children.Add(myEllipse); }
Notice how the variable myEllipse in the onLoad function is a reference to an empty Ellipse object. Next, the Fill, Width, Height, Stroke, and StrokeThickness attributes of
137
138
Chapter 6
n
Silverlight and the DOM
the Ellipse object are initialized. Notice how the Canvas.Top and Canvas.Left attributes are initialized: myEllipse["Canvas.Top"] = 50; myEllipse["Canvas.Left"] = 50;
The following code adds the Ellipse object to the existing DOM, thereby enabling you to see the dynamically created blue Ellipse object: rootElement.Children.Add(myEllipse);
The last part of Listing 6.4 invokes the standard Silverlight object creation code: createSilverlight();
JavaScript and Checkerboard Patterns Figure 6.3 displays a rectangular grid of dynamically created rectangles forming a checkerboard pattern.
Figure 6.3 Creating a checkerboard dynamically in JavaScript.
JavaScript and Checkerboard Patterns
Listing 6.5 displays the contents of the HTML file Checkerboard1.html, which contains the JavaScript code for creating a checkerboard pattern dynamically. Listing 6.5
Checkerboard1.html
Silverlight Graphics var basePointX var basePointY var currentX var currentY var rowCount var colCount var cellWidth var cellHeight var strokeThickness var rectNode
= = = = = = = = =
20; 20; 0; 0; 10; 10; 30; 30; 1;
= null;
function onLoad(control, context, rootElement) { for(var row=0; row Silverlight With Mouse Events
var clickCount = 0; var myRectangle; function doLoad(control, userContext, rootElement) { myRectangle = control.content.findName("MyRect1"); myRectangle.addEventListener("MouseLeftButtonDown", "mouseLeftButtonDown"); }
Detecting Mouse Click Events function mouseLeftButtonDown(sender, args) { if(clickCount % 3 = = 0) { myRectangle.Fill = "Blue"; myRectangle.Stroke = "Yellow"; myRectangle.StrokeThickness = "8"; } else if(clickCount % 3 = = 1) { myRectangle.Fill = "Yellow"; myRectangle.Stroke = "Black"; myRectangle.StrokeThickness = "4"; } else { myRectangle.Fill = "Red"; myRectangle.Stroke = "Black"; myRectangle.StrokeThickness = "12"; } + +clickCount; }
createSilverlight();
The onLoad() JavaScript function locates the rectangle whose name is MyRect1 and initializes the global variable myRectangle with a reference to that object. Next, the code adds a MouseLeftButtonDown event handler, which means that the
157
158
Chapter 7
n
Mouse Events and Keystroke Events
JavaScript function mouseLeftButtonDown is executed whenever users click on the rectangle MyRect1, as shown here: function doLoad(control, userContext, rootElement) { myRectangle = control.content.findName("MyRect1"); myRectangle.addEventListener("MouseLeftButtonDown", "mouseLeftButtonDown"); }
The mouseLeftButtonDown() function updates the fill color, the stroke color, and the stroke thickness of the rectangle MyRect1, depending on the number of times users click: function mouseLeftButtonDown(sender, args) { if(clickCount % 3 = = 0) { myRectangle.Fill = "Blue"; myRectangle.Stroke = "Yellow"; myRectangle.StrokeThickness = "8"; } else if(clickCount % 3 = = 1) { myRectangle.Fill = "Yellow"; myRectangle.Stroke = "Black"; myRectangle.StrokeThickness = "4"; } else { myRectangle.Fill = "Red"; myRectangle.Stroke = "Black"; myRectangle.StrokeThickness = "12"; } + +clickCount; }
Notice that the global variable clickCount is incremented each time users click on the rectangle MyRect1.
Generating Rectangles via Mouse Click Events
Generating Rectangles via Mouse Click Events Consider the rectangle in Figure 7.2.
Figure 7.2 Updating a rectangle in JavaScript.
The Silverlight/XAML document AddRect1.xml in Listing 7.3 contains a named Rectangle object, and the HTML file AddRect1.html in Listing 7.4 contains the code for dynamically adding rectangles. A new rectangle will appear whenever the user clicks within the boundaries of the Silverlight object on the Web page. Listing 7.3
AddRect1.xml
Listing 7.4
AddRect1.html
159
160
Chapter 7
n
Mouse Events and Keystroke Events
Silverlight With Mouse Events var clickCount = 0; var rectWidth = 50; var rectHeight = 40; var currentX = 0; var currentY = 0; function doLoad(control, userContext, rootElement) { myRectangle = control.content.findName("MyRect1"); myRectangle.addEventListener("MouseLeftButtonDown", "mouseLeftButtonDown"); } function mouseLeftButtonDown(sender, args) { currentX = args.getPosition(null).x; currentY = args.getPosition(null).y; rect rect rect rect rect rect rect rect
= ’’; + = ’’; rect + = ’’; rect + = ’ ’; } else {
Generating Rectangles via Mouse Click Events rect + = ’ Fill = "Blue">’; rect + = ’’; rect + = ’ ’; } control = document.getElementById("Ag1"); rectNode = control.Content.CreateFromXaml(rect); control.Content.Root.Children.Add(rectNode); + +clickCount; } createSilverlight();
Listing 7.4 defines an onLoad function that locates a Silverlight/XAML rectangle and then adds a mouse event listener, as shown here: function doLoad(control, userContext, rootElement) { myRectangle = control.content.findName("MyRect1"); myRectangle.addEventListener("MouseLeftButtonDown", "mouseLeftButtonDown"); }
When a user clicks on the rectangle, the mouseLeftButtonDown function is executed, which adds a new rectangle at the current mouse location. The code in this function can be divided into three logical parts. The first part of the mouseLeftButtonDown function determines the x-coordinate and the y-coordinate of the location of the mouse click, as shown here: currentX = args.getPosition(null).x; currentY = args.getPosition(null).y;
161
162
Chapter 7
n
Mouse Events and Keystroke Events
The second part of the mouseLeftButtonDown function creates a Canvas object that contains a Rectangle object, as shown here: rect rect rect rect rect rect rect rect
= += += += += += += +=
’’; ’’; rect + = ’’; rect + = ’ ’; } else { rect + = ’ Fill = "Blue">’; rect + = ’’; rect + = ’ ’; }
The third part of the mouseLeftButtonDown function adds the newly created rectangle and increments the clickCount variable, as shown here: control = document.getElementById("Ag1"); rectNode = control.Content.CreateFromXaml(rect); control.Content.Root.Children.Add(rectNode); + +clickCount;
Experiment with this code sample to add ellipses, Be´zier curves, and any other geometric shapes that appeal to you.
Freestyle Sketching and Mouse Move Events
Freestyle Sketching and Mouse Move Events Figure 7.3 displays the result of adding a small rectangle at the current mouse location whenever the user moves his mouse.
Figure 7.3 Sketching and mouse move events.
Listing 7.5 displays the contents of the HTML file Sketch1.html, which dynamically creates and adds a rectangle to the Canvas object in Sketch1.xml (which is similar to AddRect1.xml) at the current mouse location. Listing 7.5
Sketch1.html
Silverlight With Mouse Events var clickCount = 0; var rectWidth = 1;
163
164
Chapter 7
n
Mouse Events and Keystroke Events
var rectHeight = 1; var currentX = 0; var currentY = 0; function doLoad(control, userContext, rootElement) { myRectangle = control.content.findName("MyRect1"); myRectangle.addEventListener("MouseMove", "mouseMove"); } function mouseMove(sender, args) { currentX = args.getPosition(null).x; currentY = args.getPosition(null).y; rect rect rect rect rect rect rect rect rect rect rect rect
= ""; = ’’; + = ’’; + = ’’; + = ’ ’;
"’+rectWidth+’"’; "’+rectHeight+’"’; "Black"’; "2"’; "’+currentX+’"’; "’+currentY+’"’;
control = document.getElementById("Ag1"); rectNode = control.Content.CreateFromXaml(rect); control.Content.Root.Children.Add(rectNode); + +clickCount; } createSilverlight();
Dynamically Adding and Removing Objects
The onLoad function in Listing 7.5 finds the Rectangle object whose Name is MyRect1, and then it adds a MouseMove event listener to the rectangle. Thus, the mouseMove function is executed whenever users move their mouse, as shown here: function doLoad(control, userContext, rootElement) { myRectangle = control.content.findName("MyRect1"); myRectangle.addEventListener("MouseMove", "mouseMove"); }
The mouseMove function determines the current mouse location with the following code fragment: currentX = args.getPosition(null).x; currentY = args.getPosition(null).y;
The values of currentX and currentY are used as the coordinates of the upper-left vertex for each dynamically created rectangle. The remainder of the code in Listing 7.5 is the same as the code in Listing 7.4.
Dynamically Adding and Removing Objects The XML document DeleteElement1.xml in Listing 7.6 contains the definition of a Rectangle object, and the HTML file DeleteElement1.html in Listing 7.7 demonstrates how to remove a Silverlight/XAML Rectangle object. Listing 7.6
DeleteElement1.xml
165
166
Chapter 7
Listing 7.7
n
Mouse Events and Keystroke Events
DeleteElement1.html
Silverlight With Mouse Events function doLoad(control, userContext, rootElement) { myRectangle = control.content.findName("MyRect1"); myRectangle.addEventListener("MouseLeftButtonDown", "mouseDown"); } function mouseDown(sender, args) { control = document.getElementById("Ag1"); control.Content.Root.Children.Remove(myRectangle); } createSilverlight();
Listing 7.7 contains an onLoad function that adds a mouse event listener to a rectangle, as shown here: function doLoad(control, userContext, rootElement) { myRectangle = control.content.findName("MyRect1");
Mouse Events and Multiple Dynamic Objects myRectangle.addEventListener("MouseLeftButtonDown", "mouseDown"); }
The Rectangle object whose Name attribute has value MyRect1 is defined in the XML document DeleteElement1.xml that is located in the xaml subdirectory. When a user clicks on this rectangle, the following JavaScript function mouseDown is invoked: function mouseDown(sender, args) { control = document.getElementById("Ag1"); control.Content.Root.Children.Remove(myRectangle); }
The purpose of the mouseDown function is to remove the myRectangle object from the DOM, which is accomplished by the following code: control.Content.Root.Children.Remove(myRectangle);
Listing 7.7 is a simple example that shows how to remove a Silverlight/XAML object from the DOM that contains that object. A more complicated example involves dynamically creating an array of objects. You must also set the Name attribute for every object in the array and add an event listener for each of those objects. After doing so, you can determine which object is selected when users perform a mouse-related action on a specific object. The next example illustrates how you can handle such a scenario.
Mouse Events and Multiple Dynamic Objects The HTML file Checkerboard1ME.html in Listing 7.8 demonstrates how to add a mouse event to each rectangle in a checkerboard. When a user clicks on any rectangle in the checkerboard, that rectangle is removed from the DOM. Listing 7.8
Checkerboard1ME.html
Silverlight Graphics
167
168
Chapter 7
n
Mouse Events and Keystroke Events
var basePointX var basePointY var currentX var currentY var currRow var currCol var rowCount var colCount var cellWidth var cellHeight var mouseX var mouseY var strokeThickness var index var rect var rectList var rectNode var currRect
= 20; = 20; = 0; = 0; = 0; = 0; = 5; = 5; = 60; = 60; = 0; = 0; = 1; = 0; = ""; = new Array(rowCount*colCount); = null; = null;
function onLoad(control, context, rootElement) { for(var row=0; row Silverlight With Mouse Events var keyCode = 0; var keyChar = ""; var digits
= [’0’,’1’,’2’,’3’,’4’, ’5’,’6’,’7’,’8’,’9’];
var upperCase = [’A’,’B’,’C’,’D’,’E’,’F’,’G’,’H’,’I’, ’J’,’K’,’L’,’M’,’N’,’O’,’P’,’Q’,’R’, ’S’,’T’,’U’,’V’,’W’,’X’,’Y’,’Z’]; var textArea
= null;
Processing Keystrokes function doLoad(control, userContext, rootElement) { textArea = rootElement.findName("TextArea"); rootElement.addEventListener("KeyDown", "keyDown"); rootElement.addEventListener("KeyUp", "keyUp"); } function findAlphaChar(keyCode) { if((keyCode > = 20) && (keyCode < = 29)) { return(digits[keyCode-20]); } else if((keyCode > = 30) && (keyCode < = 55)) { return(upperCase[keyCode-30]); } else if(keyCode = = 9) { return(" "); } else { //return(keyCode); return(""); } } function keyDown(sender, args) { keyCode = args.Key; keyChar = findAlphaChar(keyCode); textArea.Text = textArea.Text + keyChar; } function keyUp(sender, args) {
179
180
Chapter 7
n
Mouse Events and Keystroke Events
//textArea.Text = "KeyUp"; } createSilverlight();
Key Constructs Event handlers for mouse events have the following syntax in Silverlight/XAML, and the code is typically placed in HTML files: myRectangle.addEventListener("MouseEnter", "mouseEnter"); myRectangle.addEventListener("MouseLeave", "mouseLeave"); myRectangle.addEventListener("MouseLeftButtonDown", "mouseLeftButtonDown"); myRectangle.addEventListener("MouseLeftButtonUp", "mouseLeftButtonUp"); myRectangle.addEventListener("MouseMove", "mouseMove");
Event handlers for keystroke events have the following syntax in Silverlight/XAML, and the code is typically placed in HTML files: myRectangle.addEventListener("KeyDown", "keyDown"); myRectangle.addEventListener("KeyUp", "keyUp");
Summary
Summary This chapter focused on how to update or remove existing Silverlight/XAML objects dynamically, and also how to remove existing objects from the DOM of a Silverlight/XAML document. This type of dynamic update also relies on the capability to capture the following mouse-related events: n
mouseover
n
mouseout
n
onclick
to start animation effects
to end animation effects
and JavaScript functions for updating or deleting existing XAML
objects n
onclick and JavaScript functions for dynamically creating new XAML objects
181
This page intentionally left blank
chapter 8
Silverlight and Complex Graphics This chapter demonstrates how to use JavaScript in Silverlight/XAML to create graphics effects that are based on polar equations. The more interesting graphics effects in Silverlight/XAML (and SVG as well) are actually combinations of polar equations with other geometric objects, such as ellipses, in conjunction with a variety of linear and radial color gradients. The Silverlight/XAML code presented in this chapter uses more complicated code that also tends to be longer than the examples in previous chapters. In some cases, you will also see a significant performance penalty. For instance, Steiner1.html generates a graphics image that is based on a Steiner equation. You can specify parameter values whereby the code in Steiner1.html will dynamically create and add more than 30,000 Rectangle objects in JavaScript, and therefore the rendering time is noticeable on older, slower PCs. Incidentally, when you launch Steiner1.html, watch the memory consumption on your PC or laptop while you wait for Silverlight to render the graphics image.
Mathematical Terminology This chapter (and most of the supplementary code) contains many graphics images that are based on mathematical equations. You will often see modifications and enhancements of these equations to generate a greater variety of interesting graphics images. In such cases, the graphics images are still named
183
184
Chapter 8
n
Silverlight and Complex Graphics
after the original equation so as to convey the source of the key idea that underlies the image in question. In other cases, the graphics images depart substantially from the strict mathematical interpretation of the equation. The names of these graphics images are meant to give you an indication of the ‘‘essence’’ of the original mathematical equation, even though the generalization may depart considerably from the original equation. Many times the mathematical term for the given graphics image simply does not exist, which necessitates a mechanism for describing the images in a reasonable fashion. While the name gradientGeneralizedConeBasedOnASetOfEllipses.html might be more correct for a Silverlight/XAML document, it’s also unnecessarily unwieldy; on the other hand, the simpler and shorter name EllipticConeGradient.html conveys just as much information about the nature of the contents of the Silverlight/XAML document, provided that you keep in mind that you are dealing with a generalization rather than the strict mathematical definition. What about performance? The insertion of many dynamically created XAML objects to the XAML DOM can involve considerable overhead. Instead of inserting each object as it is created, you can create an in-memory sub-tree of dynamically created nodes and then add the root node of the sub-tree to the XAML DOM. Use this technique on several XAML documents and see if there is a significant difference in rendering time.
Generating Sine-Based Petals Figure 8.1 displays a set of sine-based petals.
Figure 8.1 A set of sine-based petals.
Generating Sine-Based Petals
The Silverlight/XAML document SineCirclePetals1.html in Listing 8.1 demonstrates how to render a set of circles based on a sine function to dynamically generate a set of sine-based petals. Listing 8.1
SineCirclePetals1.html
Silverlight Graphics var basePointX var basePointY var currentX var currentY var majorAxis var minorAxis var offsetX var offsetY var radius var smallRadius var Constant var branches var angle var maxAngle var angleDelta var strokeThickness var circleColors var colorCount var ellipseNode
= = = = = = = = = = = = = = = = = =
200; 220; 0; 0; 30; 20; 0; 0; 0; 2; 200; 5; 0; 360; 1; 1; [’Red’,’Blue’]; circleColors.length;
= null;
// ’onLoad’ function . . . function onLoad(control, context, rootElement) { for(var angle=0; angle 2D mapping: // offsetX = x + z*cos(theta); // offsetY = y + z*sin(theta); ///////////////////////////////////
Simulating 3D Effects with a Steiner Equation
The conversion equations are used to calculate the values of offsetX and offsetY: offsetX = x+z*Math.cos(baseAngle*Math.PI/180); offsetY = y+z*Math.sin(baseAngle*Math.PI/180);
Next, the values of the variables offsetX and offsetY are used to compute the coordinates of a point in the plane: currentX = basePointX+offsetX; currentY = basePointY+offsetY;
The next section of code creates a Silverlight/XAML object: ellipseNode = control.Content.CreateFromXaml(""); ellipseNode.Fill = ellipseColors[(((u+v)%2)*2)%colorCount]; ellipseNode.Width ellipseNode.Height ellipseNode["Canvas.Left"] ellipseNode["Canvas.Top"]
= = = =
eRadius; eRadius; currentX; currentY;
rootElement.Children.Add(ellipseNode);
The last section of code in Listing 8.4 contains the code that invokes the Silverlight code: createSilverlight();
Listing 8.4 contains many dynamically created Silverlight/XAML objects, so object creation code is very CPU-intensive. Consequently, the rendering time for the code in Listing 8.4 depends on the speed of your machine. As a reference point, the graphics image in Listing 8.4 renders in approximately 10 seconds on a 2GHz Pentium-based laptop.
207
208
Chapter 8
n
Silverlight and Complex Graphics
This example concludes the discussion of JavaScript functions for this chapter. You should now be able to understand virtually all the supplemental code samples.
Key Constructs You can simulate three-dimensional effects in Silverlight/XAML by computing the two-dimensional point that corresponds to a point (x,y,z) with the following equations: offsetX = x + z*cos(theta); offsetY = y + z*sin(theta);
Summary This chapter focused on defining JavaScript functions for rendering graphics images that are based on trigonometric functions or polar equations. You learned how to use polar equations as the basis for rendering visually rich graphics effects in Silverlight/XAML. The examples demonstrated how to create images that are derived from sine waves and wireframe effects with Archimedean equations. In the last example of this chapter, you also saw how to simulate three-dimensional effects. The last chapter in this book contains supplemental examples of complex graphics that incorporate additional techniques for creating even richer visual effects.
chapter 9
Bar Charts, Line Graphs, and Pie Charts This chapter demonstrates how Silverlight/XAML can be used to create bar charts, line graphs, and pie charts. Since the primary focus of this chapter is to illustrate the creation of the charts and graphs, data values are randomly generated data points. In real-world situations, you need access to real data that can reside in a database, in a dynamically generated XML document, or from a Web service. Note that all of these scenarios are beyond the scope of this book. The first part of the chapter starts with an example of rendering a bar set because this example is the basis for creating much more sophisticated bar charts. The second part of the chapter extends the concepts introduced in the first part by showing you how to render bar charts that respond to mouse events and bar charts with gradient shading. Next, you will learn how to render line graphs, followed by a three-dimensional bar chart. After you have completed this chapter, you will know how to produce charts and graphs using modularized JavaScript functions, and you will have a solid foundation from which you can create charts and graphs that support your specific needs and requirements. If you want to see the details of the JavaScript files that are included in the HTML examples in this chapter, please read the relevant section in Chapter 1, ‘‘Introduction to Silverlight.’’
Rendering Homogeneous Bar Sets Consider the set of equal-size rectangles in Figure 9.1. 209
210
Chapter 9
n
Bar Charts, Line Graphs, and Pie Charts
Figure 9.1 A bar set.
The HTML file BarSet1.xml in Listing 9.1 demonstrates how to draw a bar set of rectangles of equal width and height, alternating between red and blue. Listing 9.1
BarSet1.xml
Rendering Simple Bar Charts
Navigate to the location of the HTML file BarSet1.html and then double-click on the file to see a bar set rendered in a browser session. Listing 9.1 defines a set of Rectangle objects with equal height and width whose colors alternate between red and blue. Notice that the x-coordinate of each rectangle is incremented by 40 pixels, which produces a set of contiguous rectangles. In this book, a set of contiguous rectangles that have the same width and height will be informally referred to as a ‘‘homogeneous bar set.’’
Rendering Simple Bar Charts Figure 9.2 displays a bar chart with unlabeled vertical and horizontal axes.
211
212
Chapter 9
n
Bar Charts, Line Graphs, and Pie Charts
Figure 9.2 A bar chart.
The HTML file BarChart1.html in Listing 9.2 illustrates how to render a bar chart in which the heights of the individual bar elements are randomly generated values. Listing 9.2
BarChart1.html
Silverlight Graphics var basePointX var basePointY var currentX var currentY var offsetY var tipOffsetX var tipOffsetY var barCount var barWidth
= = = = = = = = =
50; 50; 0; 0; 0; 0; 0; 10; 30;
Rendering Simple Bar Charts var var var var var var var var var var var var
barHeight minBarHeight maxBarHeight indentX indentY strokeThickness lStroke lStrokeThickness barColors colorCount arrowWidth arrowHeight
var lineNode var polyNode var rectNode
= 0; = 20; = 300; = 10; = 10; = 1; = "Black"; = 2; = ["Red","Blue", "Green", "Yellow"]; = barColors.length; = 20; = 10; = null; = null; = null;
// ’onLoad’ function... function onLoad(control, context, rootElement) { for(var i=0; i=0 && currCol=0 && currCol>> y="def"
"
339
340
Chapter 13
n
Introduction to Scripting Languages
>>> z=x+y >>> print z abc def >>> print x.rstrip()+y abcdef
Every Python string has upper() and lower() functions that you can invoke: >>> print x abc >>> print x.upper() ABC >>> print x.upper().lower() abc
The following example shows you how to extract a substring of a given string: >>> z="abcdef" >>> shortz = z[2:4] >>> print shortz cd
Python also provides built-in functions for manipulating multiword text strings. For example, the Python split command can print the words in a sentence: >>> line = "this is a line" >>> for word in line.split(): ... print ’Word: ’,word ... Word: this Word: is Word: a Word: line
Python uses a space as the default delimiter for the split command, but you can specify other characters as well. For example, you can specify a pipe (|) as the delimiter as shown here: >>> line = "this|is|a|line" >>> for word in line.split("|"): ... print ’Word: ’,word ... Word: this Word: is Word: a Word: line
The list and join Commands in Python
Concatenating Strings and Numbers in Python Languages such as Perl and JavaScript perform string concatenation when you add a string and a number. For example, if you add the string abc and the number 3, the result is the string abc3 in Perl or JavaScript. However, in Python you must explicitly convert a number to a string before you can add it to another string: >>> x="abc" >>> y=3 >>> print x+str(y) abc3
If you try to add x and y without performing the explicit conversion, Python generates the following error message: >>> print x+y Traceback (most recent call last): File "", line 1, in TypeError: cannot concatenate ’str’ and ’int’ objects
The list and join Commands in Python The Python list function is useful for exploding a word into a list of characters (the SNOBOL language actually has an explode function that serves this very purpose!). The list of characters can then be manipulated with other stringrelated functions. For example, you can reverse the letters in a word with the following code fragment: >>> word = "abcdef" >>> wordList = list(word) >>> wordList.reverse() >>> reversedWord = "".join(wordList) >>> print reversedWord fedcba
The Python join function allows you to specify a different join character or even another string: >>> rWord2="z".join(wordList) >>> print rWord2 fzezdzczbza >>> rWord3=" AAA".join(wordList) >>> print rWord3
341
342
Chapter 13
Introduction to Scripting Languages
n
f AAA e AAA d AAA c AAA b AAA a
If you want to reverse the words in a text string, you can do the following: >>> line="this is a line" >>> wordList = line.split(" ") >>> wordList.reverse() >>> reverseLine = " ".join(wordList) >>> print reverseLine line a is this
Now that you have a basic understanding of Python variables, you are ready to learn how to perform conditional logic in Python.
Loops and Conditional Statements in Python Python supports if . . . else conditional logic to execute different blocks of code. Listing 13.1 displays the contents of Loop1.py, which demonstrates how to use such logic in a Python for loop. Listing 13.1
Loop1.py
# the numbers from 0 to 7 inclusive for x in range(8): if x = = 3: pass elif x < 5: print x else: print str(x) + " (bigger than 4)"
Open a command shell, verify that the Python executable is included in the PATH variable, and type the following: python Loop1.py
This command will generate the following output: 0 1 2 4 5 (bigger than 4) 6 (bigger than 4) 7 (bigger than 4)
Comparing pass, break, and continue in Python
Notice that the number 3 does not appear in the output, which is due to the pass statement in the code: if x = = 3: pass
In this example, you can also replace pass with continue, and you will generate the same output (the difference between these two statements will be explained a bit later). As you can probably surmise, Python also supports while statements. Listing 13.2 displays the contents of the Python script While1.py, which generates the same output as Listing 13.1. Listing 13.2
While1.py
x=0 while( x < 8 ): if x = = 3: pass elif x < 5: print x else: print str(x) + " (bigger than 4)" x += 1
Listing 13.2 generates the same output as Listing 13.1, but there is a slight difference: You must initialize the variable x and also increment x in the body of the loop. In this situation, pass and continue are not interchangeable. The next section explains why this is the case.
Comparing pass, break, and continue in Python If you replace pass with break in Listing 13.2, you will see the following output: 0 1 2
On the other hand, if you replace pass with continue in Listing 13.2, you will see the following output: 0 1 2
343
344
Chapter 13
n
Introduction to Scripting Languages
But the program seems to hang. The reason is simple: When you specify continue instead of pass, your while loop never executes the increment statement x + = 1, which means that the condition in the while statement will always be true and will cause an infinite loop. As a side note, you can use the next statement in Perl because you can increment a variable before evaluating the condition in the while statement: my($x) = 0; while($x++ < 8) { if ($x = = 3) { next; } elsif ($x < 5) { print "$x\n"; } else { print "$x (bigger than 4)\n"; } }
Packages and import Statements A package is a mechanism used in Python, Jython, Java, and Ada for avoiding name collisions. If you are unfamiliar with this concept, consider what would happen in a conference call with three people: John Smith, Dave Jones, and Dave Anderson. Clearly there will be ambiguity whenever John mentions ‘‘Dave,’’ and the only way to resolve the ambiguity is for John to specify Dave’s full name to distinguish between Dave Jones and Dave Anderson. In a similar fashion, you can think of a package as a fully qualified name for the classes that belong to the package. (Incidentally, XML uses namespaces to avoid name collisions.) A Python import statement specifies the package structure of a Python class that you want to reference in your Python code. This functionality allows you to use existing Python classes so that you do not need to write the Python code yourself. For example, instead of writing the Python code for the trigonometric sine function, you can import the appropriate Python class that already defines this
Setting Up Ruby on Your Machine
function for you. Python classes are defined in a hierarchical fashion, so you need to import classes using the dot notation. For example, if you want to import the Python class a.b.Utilities, you need to use the following import statement: from a.b import Utilities
Java uses a slightly different syntax: import a.b.Utilities;
This concludes the Python-related portion of this chapter. The rest of the chapter discusses how to set up Ruby on your machine and then provides information about basic Ruby features.
Setting Up Ruby on Your Machine The first step involves downloading the Ruby code. Navigate to the Ruby home page at http://www.ruby-lang.org/en, which has links for software downloads (Windows, Macintosh, and Unix), user groups, and job announcements. Select the download that corresponds to your operating system. For example, on a Windows machine you can download the file ruby186-26.exe to a convenient directory on your machine and then double-click on the filename or invoke the following from the command line: Ruby186-26.exe
If you press the Enter key to accept the default values, you will install Ruby in the default directory C:\Ruby. The second step involves adding Ruby to the PATH variable on your machine. On a Windows PC you can enter the following in a command shell: set PATH=c:\Ruby;%PATH%
Make sure that you replace the directory listed in bold with the appropriate directory on your machine. Alternatively, you can put the preceding set command in a file such as ruby186.bat or add the Ruby directory to your PATH variable in the Registry. On a Linux system you can type the following from the command line: PATH=/usr/local/ruby186:$PATH; export PATH
345
346
Chapter 13
n
Introduction to Scripting Languages
Once again, you need to replace the directory in bold with the appropriate location on your Linux machine. For convenience, it’s a good idea to include the preceding line in the .profile file in your home directory.
Interactive Ruby Ruby allows you to type code inside a Ruby environment, which gives you the capability to test code fragments quickly. Open a command shell, and after confirming that Ruby is included in the PATH variable, launch Ruby in interactive mode by typing the following command: irb
You will see a prompt that specifies a sequentially increasing number for each command (for the current session). Note the difference between integer division and decimal division: irb(main):001:0> 3/2 => 1 irb(main):002:0> 3.0/2.0 => 1.5
Ruby’s interactive mode allows you to define variables and execute blocks of Ruby code. This functionality has the same advantages as the interactive Python functionality. Now you are ready for examples of defining scalar and nonscalar variables in Ruby and how to assign values to them.
String Variables in Ruby Open a command shell, start an interactive session, and type the commands that are listed in bold: irb(main):001:0> "hello " + "Ruby" => "hello Ruby" irb(main):002:0> "Ruby" * 2 => "RubyRuby" irb(main):003:0> "Ruby".reverse() => "ybuR" irb(main):004:0> "Ruby".next => "Rubz"
Converting between Classes irb(main):005:0> "ruby".capitalize => "Ruby" irb(main):006:0> "Ruby".upcase => "RUBY" irb(main):007:0> "Ruby".downcase => "ruby"
Note that Ruby and Python both use a + sign for string concatenation (but Perl uses a . symbol). In Ruby, everything is treated as an object, including numbers and strings, and therefore you can apply the associated methods to a number or a string.
Converting between Classes Ruby allows you to convert a scalar value from one type to another, whether the type is string, integer, or float. For example, if you want to convert the string 123 to an integer or to a float, you can do the following: irb(main):001:0> "123".to_i => 123 irb(main):002:0> "123".to_f => 123.0 irb(main):003:0> "123".to_s => "123"
In a similar fashion, you can convert a string to an integer and a floating-point value as follows: irb(main):001:0> "5abc".to_i => 5 irb(main):002:0> "5abc".to_f => 5.0 irb(main):003:0> "5abc".to_s => "5abc"
Finally, you can convert a floating-point number in the following manner: irb(main):001:0> "5.123".to_i => 5 irb(main):002:0> "5.123".to_s => "5.123"
347
348
Chapter 13
n
Introduction to Scripting Languages
irb(main):003:0> "5.123".to_f => 5.123
You can assign a text string to a variable and print its value as follows: irb(main):001:0> message = "Hello, Ruby" => "Hello, Ruby" irb(main):002:0> puts message Hello, Ruby => nil
By convention, Ruby scripts have the extension .rb. If you want to invoke the Ruby script hello1.rb, simply type the following command: ruby hello1.rb
Using for and while Loops in Ruby Listing 13.3 displays the contents of the Ruby script ForWhile1.rb, which demonstrates how to use for loops and while loops in Ruby. Listing 13.3
ForWhile1.rb
index = 0 puts "start of for loop . . . " 3.times do index + = 1 puts index.to_s end puts puts "start of while loop . . . " index = 0 while index < 4 puts index.to_s index + = 1 end
Open a command shell, verify that the Ruby executable is contained in the PATH variable, and type the following command: ruby ForWhile1.rb
Conditional Logic in Ruby
This command will generate the following output: start of for loop . . . 1 2 3 start of while loop . . . 0 1 2 3
Conditional Logic in Ruby Ruby supports conditional logic for executing different blocks of code. Listing 13.4 displays the contents of the Ruby script IfElse1.rb, which demonstrates how to use if . . . else logic in Ruby. Listing 13.4
IfElse1.rb
index = 0 puts "start of for loop . . . " 7.times do if( index % 2 = = 0 ) puts "Even number: " + index.to_s else puts "Odd number: " + index.to_s end index + = 1 end
Open a command shell and type the following command: ruby IfElse1.rb
This command generates the following output: start of for loop . . . Even number: 0 Odd number: 1
349
350
Chapter 13 Even number: Odd number: Even number: Odd number: Even number:
Introduction to Scripting Languages
n
2 3 4 5 6
Ruby also supports if . . . elsif logic: index = 0 7.times do if( index < 2 ) puts "Less than two:" + index.to_s elsif( index < 5) puts "Less than five:" + index.to_s else puts "Less than 7: " + index.to_s end index + = 1 end
Arrays and Iterators in Ruby Ruby supports arrays and a mechanism for iterating through the items in Ruby arrays. Listing 13.5 displays the contents of the Ruby script Arrays1.rb, which demonstrates how to iterate through an array of numbers in Ruby. Listing 13.5
Arrays1.rb
index = 0 myArray = ["a","b",";c","d","e"] myArray.each do |item| puts "Item "+index.to_s+" = "+item index + = 1 end
Open a command shell and type the following command: ruby Arrays1.rb
This command generates the following output: Item 0 = a Item 1 = b
Hashes in Ruby Item 2 = c Item 3 = d Item 4 = e
Ruby has a slightly unusual syntax for iterating through the items in an array, but it is flexible and powerful. For example, the following loop will produce the same output as Listing 13.5: 5.times do |index| item = myArray[index] puts "Item "+index.to_s+" = "+item end
You can use the length of the array rather than a hard-coded value as follows: myArray.length.times do |index| item = myArray[index] puts "Item "+index.to_s+" = "+item end
If you want to sort the items in an array, you can do the following: index = 0 myArray = ["a","b","c","d","e"] myArray.sort.each do |item| puts "Item "+index.to_s+" = "+item index + = 1 end
Hashes in Ruby A Ruby hash is a set of name/value pairs and is similar to a Perl hash. Listing 13.6 displays the contents of the Ruby script Hashes1.rb, which demonstrates how to iterate through the items in a Ruby hash. Listing 13.6
Hashes1.rb
myHash = {"a" => "1", "b" => "2", "c" => "3", "d" => "4", "e" => "5"} myHash.each do |key, value| puts key + " has value " + value end
351
352
Chapter 13
Introduction to Scripting Languages
n
Open a command shell and type the following command: ruby Hashes1.rb
As you probably expect, this command generates the following output: a b c d e
has has has has has
value value value value value
1 2 3 4 5
Ruby also provides other built-in functions for manipulating Ruby hashes, but they will not be discussed in this chapter.
Defining Functions in Ruby Listing 13.7 displays the contents of the Ruby script Function1.rb, which demonstrates how to define functions in Ruby. Listing 13.7
Function1.rb
myArray = ["a","b","c","d","e"] def displayItem(theArray, index) item = theArray[index] puts "item = "+item.to_s end displayItem(myArray, 0) displayItem(myArray, 3)
Listing 13.7 generates the following output: item = a item = d
Notice that user-defined functions start with the keyword def and are terminated by the keyword end. After you define a Ruby function, you can invoke the function by name and also by passing in any variables that are required to execute that function. For example, you can execute the Ruby function displayItem as shown here: displayItem(myArray, 0) displayItem(myArray, 3)
Defining Classes in Ruby
Defining Classes in Ruby Listing 13.8 displays the contents of the Ruby script Classes1.rb, which demonstrates how to define and instantiate a class in Ruby. Listing 13.8
Classes1.rb
class SimpleClass def initialize(newArray) @array = newArray end def displayArray() @array end end
myArray = ["a","b","c","d","e"] simple = SimpleClass.new(myArray) puts simple.displayArray()
Open a command shell and type the following command: ruby Classes1.rb
This command will generate the following output: a b c d e
As you look at the code in Listing 13.8, you might be wondering how the printed array was actually initialized. When you instantiate a Ruby class, the initialize method is executed (if it exists). In this example, the Ruby array myArray is initialized here: myArray = ["a","b","c","d","e"]
Next, the Ruby class SimpleClass is instantiated and assigned to the Ruby variable simple: simple = SimpleClass.new(myArray)
353
354
Chapter 13
n
Introduction to Scripting Languages
The class SimpleClass has an initialize method, which assigns the contents of the array myArray to the internal variable array. Next, the following code line invokes the displayArray method: puts simple.displayArray()
The displayArray method merely displays the items in the variable array (which is the same as the contents of myArray): def displayArray() @array end
Notice that the Ruby method displayArray does not require an explicit for loop to iterate through an array and print each of its items. This example illustrates the highly compact nature of Ruby.
Key Constructs This section provides a short list of some core features of Python and Ruby. Python supports scalar variables, lists, and hashes: >>> a=4 >>> x=[1,2,3,4] >>> d = {’a’:1, ’c’:2,’b’:3}
Python provides built-in functions that allow you to manipulate dictionaries: >>> >>> >>> >>> >>> >>> >>>
d = {’a’:1, ’c’:2,’b’:3} items = d.items() items.sort() items.reverse() keys = d.keys() values = d.values() values.reverse()
Python supports for loops: for x in range(8): print x
Python supports while loops: x=0 while( x < 8 ): print x x += 1
Key Constructs
Python also supports a rich set of built-in functions that enable you to perform sophisticated string manipulations. Ruby provides built-in functions for manipulating string variables: irb(main):001:0> "hello " + "Ruby" => "hello Ruby" irb(main):002:0> "Ruby" * 2 => "RubyRuby" irb(main):003:0> "Ruby".reverse() => "ybuR" irb(main):004:0> "Ruby".next => "Rubz" irb(main):005:0> "Ruby".capitalize => "Ruby" irb(main):006:0> "Ruby".upcase => "RUBY" irb(main):007:0> "Ruby".downcase => "ruby"
Ruby supports for loops: index = 0 3.times do index + = 1 puts index.to_s end
Ruby supports while loops: index = 0 while index < 4 puts index.to_s index + = 1 end
Ruby supports conditional logic: index = 0 7.times do if( index % 2 = = 0 )
355
356
Chapter 13
n
Introduction to Scripting Languages
puts "Even number: " + index.to_s else puts "Odd number: " + index.to_s end index + = 1 end
Ruby supports arrays: index = 0 myArray = ["a","b","c","d","e"] myArray.each do |item| puts "Item "+index.to_s+" = "+item index + = 1 end
Ruby supports hashes: myHash = {"a" => "1", "b" => "2", "c" => "3", "d" => "4", "e" => "5"} myHash.each do |key, value| puts key + " has value " + value end
Summary The first part of this chapter showed you how to install Python on your machine, and then you learned about some of the basic features of Python. You learned how to define scalar variables such as numbers and strings and then how to use Python’s built-in functions to manipulate those variables. Next, you learned how to define Python lists and Python hashes and how to manipulate them via Python’s built-in functions. Then you saw how to define for loops and while loops and how to define conditional logic in Python.
Summary
In a similar fashion, the second part of this chapter showed you how to install Ruby on your machine, followed by code fragments that illustrated how to define and manipulate scalar variables, arrays, and hashes in Ruby. Finally, you saw how to define for loops and while loops and how to define conditional logic in Ruby. There are many other features available in Python and Ruby that were not discussed in this chapter, and you can find entire books devoted to these scripting languages. However, you already have sufficient knowledge of both Python and Ruby to generate Silverlight/XAML documents and invoke IronPython scripts from Silverlight/XAML, all of which is covered in the next chapter.
357
This page intentionally left blank
chapter 14
Silverlight and Scripting Languages This chapter is devoted to using scripting languages to generate Silverlight/ XAML documents programmatically. The first part of this chapter shows you examples of Python scripts, and the second part contains similar examples using Perl scripts. The last part of this chapter presents examples of dynamically generating Silverlight/XAML objects via IronPython scripts. The code samples in this chapter are intentionally short because their purpose is to familiarize you with coding techniques that are available in various scripting languages. Although the code samples in this chapter usually generate a Silverlight/ XAML document that is two or three pages, these scripts can also generate hundreds or thousands of Silverlight/XAML objects. Moreover, the scripts in this chapter can be executed on a regularly scheduled basis via a scheduler (e.g., the Linux cron utility). Consequently, you can set up an automated process whereby you can extract or retrieve data in one format (e.g., text files) to generate in another format (e.g., Silverlight/XAML documents). In general, scripting languages can be very handy when you need to perform intermediate tasks that are part of a larger business-related process. Keep these points in mind as you learn the features of the scripting languages that are discussed in this chapter.
359
360
Chapter 14
n
Silverlight and Scripting Languages
In previous chapters, each code sample consisted of four files: an HTML file, two JavaScript files, and a XAML file. In this chapter, each code sample consists of the four files that you have seen previously, as well as an additional Python file (or Ruby file), for a total of five files.
Generating XML from Text Files Text files are very useful for transferring and sharing data between different applications and systems. For example, users can export spreadsheet data as an ASCII text file and then import the contents of that text file into another spreadsheet on another system (which can be local or remote). As you probably know, databases usually provide tools for importing data from text files and also exporting tables as text files. In addition, programming languages enable you to read, create, and update data in text files. In recent years, XML has become important in the business world, and now it is commonplace for spreadsheets (and databases) to provide XML-based import/export capabilities. However, many systems store their data in proprietary formats, and transferring portions of data between different systems requires custom code. The task of generating XML documents from text files can vary in time, effort, and complexity, and many times you can accomplish this task in a scripting language. For example, you can use languages such as Python or Perl to create a text file from data in a database table and then generate a Silverlight/XAML document that contains a collection of charts and graphs that visualize that data. This generic scenario is very flexible because it is applicable to tables containing employee data, transactional data, payroll data, accounts receivable data, and so forth. Now that you understand the rationale for generating XML data via scripting languages, let’s take a look at some examples of generating Silverlight/XAML documents via Python scripts.
Generating a Silverlight Document with Python The Python script PyRect1.py in Listing 14.1 generates a Silverlight/XAML document that contains a Silverlight/XAML Rectangle object, which is displayed in Listing 14.2.
Generating a Silverlight Document with Python Warning Due to changes in the Silverlight 2.0 beta, it appears that the code in this chapter will work only in Silverlight 2.0 alpha. While it’s possible to invoke IronPython in Silverlight 2.0 beta, you will need to use a tool such as Visual Studio 2008 to create XAP files. Here are several useful links that will help you get started: http://blogs.msdn.com/katriend/archive/2008/03/16/silverlight-2-structure-of-the-new-xap-filesilverlight-packaged-application.aspx http://www.voidspace.org.uk/ironpython/silverlight/silverlight_application.shtml http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2008/03/05/Xap_2100_ -App_2100_-Pow_2100_-Packaging-and-Application-Startup-in-Silverlight-2-Beta-1-_2D00_ -Part-1.aspx http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2008/03/05/Xap_2100_ -App_2100_-Pow_2100_-Packaging-and-Application-Startup-in-Silverlight-2-Beta-1-_2D00_ -Part-2.aspx
Listing 14.1
PyRect1.py
# A Silverlight/XAML rectangle print "" print " " print " "
Listing 14.2
PyRect1.xml
After you have added the directory containing the Python executable to your PATH variable, you can generate the Silverlight/XAML document displayed in Listing 14.2 by invoking Python from the command line as follows: python PyRect1.py >PyRect1.xml2
The preceding filename PyRect1.xml2 ensures that you will not inadvertently overwrite the contents of the file PyRect1.xml.
361
362
Chapter 14
Silverlight and Scripting Languages
n
Listing 14.1 is very simple: It consists of a set of print statements to print each line of Silverlight/XAML code. While this technique is for fine small Silverlight/ XAML documents, this technique is cumbersome and unwieldy for documents that are more than several pages in length. A slightly better approach is demonstrated in the next example.
Generating Bar Sets with Python The Python script PyBarSet1.py in Listing 14.3 generates the Silverlight/XAML document PyBarSet1.xml in Listing 14.4. Listing 14.3
PyBarSet1.py
# generate a bar set basePointX basePointY xPosition yPosition barWidth barHeight barCount barColors currColor index
= = = = = = = = = =
50 50 0 0 40 100 8 ["Red","Blue"] "" 0
print "" for index in offsetX offsetY currColor
range(barCount): = basePointX + index*barWidth = basePointY = barColors[index % 2]
# dynamically create a rectangle xmlStr = ’’+ "\n" print xmlStr
Generating Bar Sets with Python + +index print ""
Open a command shell, and after including the Python executable in the PATH variable, type the following command: python PyBarSet1.py >PyBarSet1.xml
The Silverlight/XAML document PyBarSet1.xml in Listing 14.4 is generated by the Python script in Listing 14.3. Listing 14.4
PyBarSet1.xml
363
364
Chapter 14
n
Silverlight and Scripting Languages
Listing 14.6 can be enhanced in various ways, such as reading the bar heights from a text file or a database table. Another enhancement is to add horizontal and vertical axes with appropriate labels. You can also perform validation on the data, such as ensuring that all the data values are positive numbers. The Python code in Listing 14.6 can be easily extended to generate threedimensional bar charts: Simply add an upper and right-side parallelogram to create a shaded effect. You can also convert the JavaScript code in Chapter 9, ‘‘Bar Charts, Line Graphs, and Pie Charts,’’ to Python-based scripts that can generate charts and graphs. The advantage of using Python code is that you can dynamically generate charts and graphs using data that can be retrieved from various sources, including Web services, databases, or a file on the file system. In addition, the Python code can be invoked programmatically to produce on-demand graphics. You can also develop a set of Python-based server-side scripts for dynamically generating Silverlight/XAML code that can be rendered in an HTML page, in a manner that is similar to the Java servlet code samples in Chapter 15, ‘‘Silverlight and Java.’’
Generating a Silverlight Document with Ruby The Ruby script RbRect1.rb in Listing 14.5 generates the Silverlight/XAML document RbRect1.xml, which is displayed in Listing 14.6. Listing 14.5
RbRect1.rb
# A Silverlight/XAML rectangle puts "" puts " " puts ""
Listing 14.6
RbRect1.xml
Generating Bar Sets with Ruby
After you have added the directory containing the Ruby executable to your PATH variable, you can generate the Silverlight/XAML document displayed in Listing 14.2 by invoking Ruby from the command line as follows: ruby RbRect1.rb >RbRect1.xml
The Ruby script in Listing 14.5 contains of a set of puts statements that print each line of Silverlight/XAML code. As you saw in the Python-based code, this technique is fine for generating small Silverlight/XAML documents, but not for large documents. A better approach involves a for loop, as demonstrated in the next example.
Generating Bar Sets with Ruby Listing 14.7 displays the contents of the Ruby script RbBarSet1.rb, which generates the Silverlight/XAML document RbBarSet1.xml that is displayed in Listing 14.8. Listing 14.7 # A bar set basePointX basePointY xPosition yPosition barWidth barHeight barCount barColors currColor index
RbBarSet1.rb = = = = = = = = = =
50 50 0 0 40 100 8 ["Red","Blue"] "" 0
puts "" #for index in range(barCount): barCount.times do offsetX = basePointX + index*barWidth offsetY = basePointY currColor = barColors[index % 2]
365
366
Chapter 14
n
Silverlight and Scripting Languages
# dynamically create a rectangle xmlStr = ’’+ "\n" puts xmlStr index + = 1 end puts ""
Listing 14.8
RbBarSet1.xml
Open a command shell, verify that the Ruby executable is included in your PATH variable, and then type the following at the command line: ruby RbBarSet1.rb > RbBarSet1.xml
Generating a Silverlight Document with Perl Although we have not discussed the Perl scripting language, your knowledge of Python will help you understand the Perl scripts that are included in this chapter. You can download Perl for Windows, Macintosh, Linux, and Solaris from http:// www.activestate.com/store/download.aspx?prdGUID=81fbce82-6bd5-49bc-a91508d58c2648ca. After you have downloaded Perl and performed the straightforward installation on your system, and, if necessary, added the Perl executable to the PATH variable, you are ready to invoke Perl from the command line. The Perl script PlRect1.pl in Listing 14.9 generates a Silverlight/XAML document that renders the Silverlight/XAML document PlRect1.xml, which is displayed in Listing 14.10. Listing 14.9
PlRect1.pl
use strict; print ’’ . "\n"; print print print print print print
’ ’ . "\n"; "\n";
Listing 14.10
PlRect1.xml
367
368
Chapter 14
n
Silverlight and Scripting Languages
Open a command shell, and after ensuring that the Perl executable is in the PATH variable, type the following command: perl -w PlRect1.pl >PlRect1.xml
The Perl script in Listing 14.9 contains of a set of print statements that print each line of Silverlight/XAML code. The next example illustrates how to write a Perl script for generating a Silverlight/XAML document that contains a bar set.
Generating Bar Sets with Perl Listing 14.11 displays the contents of the Perl script PlBarSet1.pl, and Listing 14.12 displays the contents of the Silverlight/XAML document PlBarSet1.xml. Listing 14.11 PlBarSet1.pl use strict; # STEP 1: initialize variables my($basePointX) = 50; my($basePointY) = 50; my($xPosition) = 0; my($yPosition) = 0; my($barWidth) = 40; my($barHeight) = 100; my(@barColors) my($colorCount) my($currColor) my($index)
= = = =
("Red", "Green", "Blue", "Yellow"); scalar(@barColors); ""; 0;
# STEP 2: print header information print ’’ . "\n"; # STEP 3: generate bar-related information for($index=0; $indexPlBarSet1.xml2
The output filename PlBarSet1.xml2 ensures that you will not overwrite the contents of the file PlBarSet1.xml. At this point you now know how to generate simple Silverlight/XAML documents using Python, Ruby, and Perl. All the examples that you have seen involve
369
370
Chapter 14
n
Silverlight and Scripting Languages
objects, but you can use the same techniques to generate other Silverlight/XAML objects. Rectangle
The second part of this chapter contains examples of combining Silverlight/ XAML with IronPython code.
Silverlight and IronPython The examples that you have seen in previous chapters always involved four files: an HTML file, two JavaScript files, and an XML file. A Silverlight application that invokes IronPython code requires five files: an HTML file, two JavaScript files, an XML file, and an IronPython script. Here is a minimal example that illustrates what must be done when you need to execute IronPython code. Let’s call our Silverlight application Ellipse1, which means that the five required files will be named as follows: n
Ellipse1.html
n
js/Silverlight.js
n
js/CreateSilverlightEllipse1.js
n
xaml/Ellipse1.xml
n
xaml/Ellipse1.py
Note that the first three files are the same as a non-Python Silverlight application. The fourth file requires a very small change: It must contain a reference to the IronPython script that you need to execute (i.e., the fifth file, Ellipse1.py, in the preceding list). Listing 14.13 displays the contents of the XML file Ellipse1.xml, and Listing 14.14 displays the contents of the IronPython script Ellipse1.py. Listing 14.13 Ellipse1.xml
Silverlight and IronPython
Listing 14.14
Ellipse1.py
# root is the name of the top level canvas # and is available in this namespace def OnLoad(sender, event): ellipse1 = root.FindName("Ellipse1") (Code has been omitted here)
Listing 14.14 does not display the complete contents of Ellipse1.py because the current discussion focuses on the manner in which Silverlight/XAML and IronPython code share data. Thus, the complete code listing is not required in this section. There are three important points to notice in the code. The first point is the following line of code in Listing 14.13:
This is the line of code that links the XML document Ellipse1.xml with the IronPython script file Ellipse1.py. The second point involves the following line of code in Listing 14.14: ellipse1 = root.FindName("Ellipse1")
The variable root is the top-level Canvas object in the XML document Ellipse1 .xml, and it is made available to the IronPython code. Thus, the previous line of code (defined in Ellipse1.py) will locate the Ellipse object that is defined in Ellipse1.xml. In this code sample, nothing has been done to the Ellipse object, but the other examples in this chapter will show you how to manipulate attributes of existing Silverlight/XAML objects dynamically and also how to create new objects dynamically. There is a third and final point that you need to keep in mind. The IronPython script Ellipse1.py contains the Python method OnLoad. The reason that this method is executed is because of the following instruction in Ellipse1.xml:
371
372
Chapter 14
n
Silverlight and Scripting Languages
Contrast the preceding instruction with the following instruction that would normally be included in a JavaScript file that is associated with non-Python code: events:{onError:null, onLoad:onLoad}, context:null});
The preceding line of code refers to a JavaScript function onLoad, defined in the associated HTML file, and not to a method that is defined in an IronPython script. Now that you understand the manner in which IronPython code can be referenced in an XML document, you will be able to understand the examples in the rest of this chapter.
Updating a Rectangle in IronPython The example in this section illustrates how to update a Silverlight/XAML Rectangle object in an IronPython script. Note that the three files Rectangle1.html, Silverlight.js, and CreateSilverlightRectangle1.js follow the identical coding style that you have seen throughout this book, so they will not be presented in this example. The XML document Rectangle1.xml in Listing 14.15 references the IronPython script file Rectangle1.py in Listing 14.16, which modifies a Silverlight/XAML object defined in Rectangle1.xml. Listing 14.15 Rectangle1.xml
Listing 14.16 Rectangle1.py # root is the name of the top level canvas # and is available in this namespace
IronPython and Mouse Events def OnLoad(sender, event): rectangle1 = root.FindName("Rectangle1") rectangle1.Width = 300 rectangle1.Height = 100
The XML document Rectangle1.xml in Listing 14.15 references the IronPython script Rectangle1.py, which modifies a Silverlight/XAML object that is defined in Rectangle1.xml. Let’s examine the three important points in this code sample. The first point is the manner in which the XML document Rectangle1.xml references the IronPython script Rectangle1.py, as shown here:
The second point is the following line of code in Listing 14.14: rectangle1 = root.FindName("Rectangle1")
The variable root is the top-level Canvas object in the XML document Rectangle1.xml, and it is made available to the IronPython code. Thus, the previous line of code (defined in Rectangle.py) will locate the Silverlight/XAML Rectangle object that is defined in Rectangle.xml. Notice that the Silverlight/XAML Rectangle object has an initial width of 100, as specified in the file Rectangle1.xml. However, the IronPython script Rectangle1.py modifies this attribute with the following code fragment: rectangle1.Width
= 300
Thus, when you launch the HTML file Rectangle1.html in a browser, the rendered Rectangle object will have a width of 300 instead of 100. The third point involves the following line of code:
This line of code references the Python method OnLoad (defined in Rectangle1.py), which updates the Rectangle object that is defined in Rectangle1.xml.
IronPython and Mouse Events This example illustrates how to define mouse-related code in IronPython that can modify a Silverlight/XAML Rectangle object that is defined in an XML document.
373
374
Chapter 14
n
Silverlight and Scripting Languages
The XML document Rectangle2.xml in Listing 14.17 references the IronPython script file Rectangle2.py, which modifies a Silverlight/XAML object defined in Rectangle2.xml that is displayed in Listing 14.18. Listing 14.17 Rectangle2.xml
Listing 14.18 Rectangle2.py # root is the name of the top level canvas # and is available in this namespace from System.Windows import Controls from System.Windows import Media def OnLoad(sender, event): global yellowBrush, blueBrush, tb, rectangle1 yellowBrush = Media.SolidColorBrush() yellowBrush.Color = Media.Colors.Yellow blueBrush = Media.SolidColorBrush() blueBrush.Color = Media.Colors.Blue # find the existing rectangle object rectangle1 = root.FindName("Rectangle1") # add mouse event handles to the rectangle rectangle1.MouseLeftButtonDown + = on_RectMouseDown rectangle1.MouseLeftButtonUp + = on_RectMouseUp rectangle1.MouseEnter + = on_RectMouseEnter rectangle1.MouseLeave + = on_RectMouseLeave
IronPython and Mouse Events # create a new textblock tb = Controls.TextBlock() tb.Text = "Hello from IronPython Script" tb.FontSize = 28 # add mouse event handlers to the textblock tb.MouseEnter + = on_TextMouseEnter tb.MouseLeave + = on_TextMouseLeave root.Children.Add(tb) def on_RectMouseDown(sender, eventArgs): rectangle1.Fill = blueBrush rectangle1.Height = 200 def on_RectMouseEnter(sender, eventArgs): rectangle1.Width = 400 def on_RectMouseLeave(sender, eventArgs): rectangle1.Width = 100 def on_RectMouseUp(sender, eventArgs): rectangle1.Fill = yellowBrush rectangle1.Height = 100 def on_TextMouseEnter(sender, eventArgs): tb.Opacity = 0.5 def on_TextMouseLeave(sender, eventArgs): tb.Opacity = 1
Listing 14.17 starts with the definition of the usual top-level Canvas object, followed by a line of code that references the IronPython script Rectangle2.py:
The next line in Listing 14.17 specifies the method OnLoad (defined in the IronPython script Rectangle2.py):
The last code portion in Listing 14.17 defines a Silverlight/XAML Rectangle object:
375
376
Chapter 14
n
Silverlight and Scripting Languages
The IronPython code in Listing 14.18 adds a set of mouse-related event listeners to the Silverlight/XAML Rectangle object that is defined in Listing 14.17. The first code section in Listing 14.18 specifies two import statements that are required later in the code: from System.Windows import Controls from System.Windows import Media
The next section of code in of Listing 14.18 defines the method OnLoad, which declares a set of variables as global so that they can be referenced throughout the IronPython code, as shown here: global yellowBrush, blueBrush, tb, rectangle1
The next code section in Listing 14.18 references the earlier import statement to define two colors, as shown here: yellowBrush = Media.SolidColorBrush() yellowBrush.Color = Media.Colors.Yellow blueBrush = Media.SolidColorBrush() blueBrush.Color = Media.Colors.Blue
The next code section in Listing 14.18 finds the Silverlight/XAML Rectangle object that is defined in the XML document Rectangle1.xml, as shown here: # find the existing rectangle object rectangle1 = root.FindName("Rectangle1")
The next code fragment in Listing 14.18 adds four mouse down event handlers to the Rectangle object, as shown here: # add mouse event handles to the rectangle rectangle1.MouseLeftButtonDown + = on_RectMouseDown rectangle1.MouseLeftButtonUp + = on_RectMouseUp rectangle1.MouseEnter + = on_RectMouseEnter rectangle1.MouseLeave + = on_RectMouseLeave
The code for the Python method on_RectMouseDown is shown here: def on_RectMouseDown(sender, eventArgs): rectangle1.Fill = blueBrush rectangle1.Height = 200
When a user clicks on the Rectangle object, the preceding method changes the Fill attribute of the Rectangle object to Blue, and the Height attribute is set to 200. The other three methods contain different yet similar code.
IronPython and Dynamic Object Creation
The other remaining code section in Listing 14.18 involves the initialization of a Silverlight/XAML Textblock element: # create a new textblock tb = Controls.TextBlock() tb.Text = "Hello from IronPython Script" tb.FontSize = 28
Notice that the IronPython variable tb is initialized by referencing the other import statement that is listed at the top of Listing 14.18. The mouse-related code for the TextBlock object is shown here: # add mouse event handlers to the textblock tb.MouseEnter + = on_TextMouseEnter tb.MouseLeave + = on_TextMouseLeave
The dynamically created Silverlight/XAML TextBlock object is added to the DOM with the following line of code: root.Children.Add(tb)
IronPython and Dynamic Object Creation The example in this section illustrates how to dynamically create a Rectangle object in IronPython. The XML document DynamicRect1.xml in Listing 14.19 references the IronPython script file DynamicRect1.py, which dynamically creates a Rectangle object and appends it to the DOM structure in DynamicRect1.xml, which is displayed in Listing 14.20. Listing 14.19
DynamicRect1.xml
377
378
Chapter 14
n
Silverlight and Scripting Languages
Listing 14.20 DynamicRect1.py # root is the name of the top level canvas # and is available in this namespace from System.Windows import Controls from System.Windows import Media from System.Windows import XamlReader def OnLoad(sender, event): # dynamically create a rectangle xmlStr = ’’ xmlStr + = ’’ dynRect = XamlReader.Load(xmlStr) root.Children.Add(dynRect)
Listing 14.19 is virtually identical to Listing 14.17, so it will not be discussed in this section. Listing 14.20 starts with three import statements, two of which you saw in Listing 14.18. The third import statement is used to convert a text string into a Silverlight/XAML object. The next code section in Listing 14.20 defines the OnLoad method, which uses the in-line method of defining a Silverlight/XAML Rectangle object: def OnLoad(sender, event): # dynamically create a rectangle xmlStr = ’