Professional Documents
Culture Documents
See page:
2
Chapter 1
Graphics, in literal sense, means a visual presentation of designs, shapes, drawings, and text, which is often used to view particular information. Graphics combine text, illustration, color, and so on. Animation is the process of sequentially arranging these graphics to create an illusion of movement. Multimedia includes a combination of text, audio, video, animation, and graphic contents. Windows Presentation Foundation (WPF) includes support for high quality 2-D and 3-D graphics, animation, and media features, which enable you to add graphics, transition effects, sound, and video to your applications. WPF provides advanced drawing and animation features that were previously available only for specialized libraries such as Graphics Device Interface (GDI) and GDI+. In this chapter, you learn about the graphics, animation and multimedia features of WPF. This chapter covers a detailed overview of the use of graphics, animation, and multimedia in WPF 3.5. In the later sections of this chapter, you learn about creating graphics, animation, and multimedia in WPF.
2-D Graphics
The 2-D graphics are the primitives that are specified by a set of points on a coordinate system, such as lines, curves, and figures. In this section, you will learn about: Shapes in WPF Geometries in WPF Brushes in WPF The Drawing Class Lets discuss these now in detail.
Shapes in WPF
The most important and the simplest way to draw 2-D graphics in WPF user interface are to use Shapes. Shapes in WPF represent Line, Ellipse, Path, Polygon, Polyline, and Rectangle. You can combine these shapes to create a complex graphic. Shapes in WPF are derived from the FrameworkElement class and can be drawn
simply using XAML (Extensible Application Markup Language). The description of different types of Shape in WPF or the Shape class in WPF are listed in Table 1.1: Table 1.1: Shape Class
Class
Line Ellipse Path Polygon Polyline Rectangle
Description
Draws a line between two points Draws a ellipse Draws curve and complex shapes Draws a connected series of lines that form a closed shape Draws a series of connected straight line Draws a rectangle
The common properties of all the Shape class in WPF are listed in Table 1.2: Table 1.2: Common Properties of Shape Class
Property
Stroke StrokeThickness Fill
Description
Paints the shape outline Specifies the thickness of the shape outline Paints the interior the shape
The Shape objects derive themselves from UIElement class. You can use the Shape objects inside the Container controls, as discussed earlier in Chapter 17, Working with WPF 3.5 Controls, Resources, Styles, Templates, and Commands. The Canvas container control is a good choice for the Shape objects because it supports absolute positing of its child elements. The Shape class is an abstract class and it provides a base class for the Shape elements in WPF. The inheritance hierarchy of the Shape class is as follows:
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Media.Visual System.Windows.UIElement System.Windows.FrameworkElement System.Windows.Shapes.Shape
The noteworthy properties of the Shape class are listed in Table 1.3: Table 1.3: Properties of Shape class
Property
DefiningGeometry GeometryTransform RenderedGeometry Stroke StrokeEndLineCap StrokeLineJoin StrokeMiterLimit StrokeStartLineCap StrokeThickness
Description
Retrieves a value that represents the Geometry of the Shape Retrieves a value that represents a Transform that is applied to the geometry of a Shape prior to when it is drawn Retrieves a value that represents the final rendered Geometry of a Shape Gets or sets the Brush that specifies how the Shape outline is painted Gets or sets a PenLineCap enumeration value that describes the Shape at the end of a line Gets or sets a PenLineJoin enumeration value that specifies the type of join that is used at the vertices of a Shape Gets or sets a limit on the ratio of the miter length to half the StrokeThickness of a Shape element Gets or sets a PenLineCap enumeration value that describes the Shape at the start of a Stroke Gets or sets the width of the Shape outline
Chapter 1
Geometries in WPF
The geometries in WPF are derived from the abstract base class Geometry class. The classes that derive from the Geometry class define geometric shapes in WPF. The Geometry objects are used for clipping and rendering 2-D graphics in WPF. In Table 1.1, you learned about the different Shape elements available in WPF. One of them was the Path object. The Path class has the ability the draw any simple shape, group of shapes, or more complex curves. These shapes and curves are described using the Geometry object. To use the Path class, you first need to create Geometry and then use it to set the Data property of the Path class. The basic difference between Path and Geometry is that Geometry defines a Shape and Path allows you to draw that Shape. The Path class actually uses Geometry to describe its content. The inheritance hierarchy of the Geometry class is as follows:
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Freezable System.Windows.Media.Animation.Animatable System.Windows.Media.Geometry
The noteworthy properties of the Geometry class are listed in Table 1.4: Table 1.4: Properties of Geometry Class
Property
Bounds CanFreeze DependencyObjectType Dispatcher Empty HasAnimatedProperties IsFrozen IsSealed StandardFlatteningTolerance Transform
Description
Retrieves a Rect that specifies the axis-aligned bounding box of the Geometry Retrieves a value that indicates whether the object can be made unmodifiable Retrieves the DependencyObjectType that wraps the CLR (Common Langauge Runtime) type of Geometry class Retrieves the Dispatcher this DispatcherObject is associated with Retrieves an empty object Retrieves a value that indicates whether one or more AnimationClock objects is associated with any of the Geometry class dependency properties Retrieves a value that indicates whether the object is currently modifiable Retrieves a value that declares whether this instance is currently read-only Retrieves the standard tolerance used for smoothing of the geometry. Gets or sets the Transform object applied to a Geometry
The Geometry and Shape class might look similar to you as they both describe 2-D shapes, but there are certain important differences between them. The first difference being that the Geometry class inherits from the Freezable class while the Shape class inherits from the FrameworkElement class. The Shape objects are more readily usable but the Geometry objects are more versatile. Therefore, you can say that, the Geometry class simply defines the geometry of a shape and cannot render itself. There are different types of Geometry available in WPF. The base class for all geometries is the abstract class Geometry. The classes that derive from the Geometry class can be grouped into three categories, as follows: Simple geometry Path geometry Composite geometry These categories are discussed in the upcoming section.
Simple Geometry
The simple geometry classes are used to create basic geometric shapes such as lines, rectangle, and ellipse. Basically a simple geometry class includes three classes, as given here: The LineGeometry classRepresents the geometry of a line. You can draw a line by specifying the StartPoint and EndPoint of the line. The StartPoint property gets or sets the start point of the line and the EndPoint property gets or sets the end point of the line. You can also create multiple connected
lines by using the LineSegment or Polyline segment with the PathFigure and PathGeometry classes. The LineSegment class creates a line between two points in a PathFigure and the Polyline class draws a series of connected straight lines. The RectangleGeometry classRepresents a two-dimensional rectangle. The RectangleGeoemetry is defined with the Rect structure which specifies the relative position of the rectangle and also its height and width. You can also create a rectangle with rounded edges by setting the RadiusX and RadiusY properties of the rectangle. The RectangleGeometry and the Rectangle shape are not the same. The difference lies in the values that each takes. The Rectangle shape takes only the Height and Width properties while the RectangleGeometry takes four numbers that describe the size and location of the rectangle along with the height and width. The EllipseGeometry classRepresents the geometry of a circle or ellipse. The EllipseGeometry class and the Ellipse class are not the same. The Ellipse class has a Fill, Stroke and other rendering properties which the EllipseGeometry lacks. The EllipseGeometry class defines the geometry of an ellipse.
Path Geometry
The path geometry classes include PathGeometry and StreamGeometry. The path geometry classes are used to create multiple complex figures composed of arcs, curves and lines. The path geometry classes and their functioning are listed in Table 1.5: Table 1.5: Path Geometry Classes
Class
PathGeometry StreamGeometry
Description
Draws a complex shape that is composed of arcs and curves Draws a geometric shape and is a light-weight alternative to PathGeometry
The PathGeometry class is used to define complex shapes that may be composed of arcs, curves, ellipses, lines and rectangles. The PathGeometry class defines a collection of PathFigure objects and each of PathFigure objects is composed of one or more PathSegment objects. The different types of PathSegment objects are listed in Table 1.6: Table 1.6: Type of PathSegment Object
Segment
ArcSegment BezierSegment LineSegment PolyBezierSegment PolyLineSegment PolyQuadraticBezierSegment QuadraticBezierSegment
Description
Creates an elliptical arc between two points Creates a cubic Bezier curve between two points Creates a line between two points Creates a series of cubic Bezier curve Creates a series of lines Creates a series of quadratic Bezier curve Creates a quadratic Bezier curve
The segments within the PathFigure are combined into a single geometric shape as the end point of each segment is the start point of the next segment. You can specify the point from which the first segment is drawn by setting the StartPoint property. The filled area of the PathGeometry is defined by taking all the PathFigure objects that have their IsFilled property set to True. The FillRule property is applied to determine the enclosed area. The StreamGeometry class also defines geometric shapes like the PathGeometry class. The only difference is that the StreamGeometry class is a light-weight alternative to PathGeometry. The StreamGeometry class does not support data binding, animation, or modification like the PathGeometry class.
Chapter 1
Composite Geometry
The composite geometry classes include GeometryGroup and CombinedGeometry classes. You can also create composite geometry by calling the static method Combine of the Geometry class. The composite geometry classes and their functioning are listed in Table 1.7: Table 1.7: Composite Geometry Classes
Class
GeometryGroup CombinedGeometry
Description
Creates an amalgamation of Geometry objects without combining their area Combines the area defined by two geometries
The GeometryGroup class represents a composite geometry, inclusive of other Geometry objects. The GeometryGroup class creates a composite geometry from any number of geometry objects. You can use the FillRule property of GeometryGroup to specify how the geometries are combined. The CombinedGeometry class on the other hand, represents a 2-D geometric shape defined by the combination of two Geometry objects. You can use the GeometryCombineMode property of CombinedGeometry to specify how the two geometries will be combined. The values of GeometryCombineMode can be set to: Union, Intersect, Exclude or Xor. The geometries that do not have an area disappear when the two geometries are combined.
Brushes in WPF
In WPF, you can use brushes to applying background and foreground to elements. The brushes in WPF are used to paint various shapes. The brushes in WPF derive from the Freezable base class and so supports change notification. For example, if you change a brush, the element that uses that brush repaints itself. The brushes in WPF are defined in the Brush class defined in the System.Windows.Media.Brush. The different types of brushes available in WPF are listed in Table 1.8: Table 1.8: Brush Class
Class
SolidColorBrush LinearGradientBrush RadialGradientBrush DrawingBrush ImageBrush VisualBrush
Description
Paints an area with a solid color Paints an area with linear gradient Paints an area with radial gradient Paints an area with a drawing Paints an area with an image Paints an area with a visual object
The noteworthy properties of the Brush class are listed in Table 1.9: Table 1.9: Properties of Brush class
Property
CanFreeze DependencyObjectType Dispatcher HasAnimatedProperties IsFrozen
Description
Retrieves a value that indicates whether the object can be made unmodifiable Retrieves the DependencyObjectType that wraps the CLR type of this instance Retrieves the Dispatcher, this DispatcherObject is associated with Retrieves a value that indicates whether one or more AnimationClock objects is associated with any of this objects dependency properties Retrieves a value that indicates whether the object is currently modifiable
Property
IsSealed Opacity RelativeTransform Transform
Description
Retrieves a value that declares whether this instance is currently read-only Retrieves or sets the degree of opacity of a Brush Retrieves or sets the transformation that is applied to the brush using relative coordinates Gets or sets the transformation that is applied to the brush
Different types of brushes that help you to make a WPF application are given here: SolidColorBrush LinearGradientBrush RadialGradientBrush DrawingBrush ImageBrush VisualBrush These types of brushes are discussed in the next sections.
SolidColorBrush
The SolidColorBrush defines the brush of a single color. The SolidColorBrush is used to fill graphics shapes, such as rectangle, ellipse, polygons, and paths with a single color. You can define solid color by setting the Background attribute to a string that defines a solid color. You can paint an area with a solid color by using the predefined system brush such as Red, Blue, or Yellow. You can add a SolidColorBrush to your application by adding the following code:
<SolidColorBrush .../>
The noteworthy property of SolidColorBrush is listed in Table 1.10: Table 1.10: Property of SolidColorBrush
Property
Color
Description
Gets or sets the color of this SolidColorBrush
LinearGradientBrush
The LinearGradientBrush paints an area with linear gradient, a gradually shaded fill that changes from one color to another. The LinearGradientBrush applies a smooth color change to the elements. The LinearGradientBrush creates a blended fill. This brush defines the StartPoint and EndPoint properties. They assign the two-dimensional coordinates for applying the linear gradient. The default value of the StartPoint property is 0, and EndPoint property is 1, 1 which creates a diagonal gradient. These properties allow you to choose the point where the first color begins to change and the point where the color change ends with the final color. To create a gradient, you need to add one GradientStop for each color and place each color in your gradient using the Offset value from 0 to 1. You can add a LinearGradientBrush to your application by adding the following code:
<LinearGradientBrush> <!-- GradientStops --> </LinearGradientBrush>
Chapter 1
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Freezable System.Windows.Media.Animation.Animatable System.Windows.Media.Brush System.Windows.Media.GradientBrush System.Windows.Media.LinearGradientBrush
The noteworthy properties of the LinearGradientBrush are listed in Table 1.11: Table 1.11: Properties of LinearGradientBrush
Property
ColorInterpolationMode EndPoint GradientStops MappingMode SpreadMethod StartPoint
Description
Gets or sets a ColorInterpolationMode enumeration that specifies how the gradients colors are interpolated Gets or sets the ending two-dimensional coordinates of the linear gradient Gets or sets the brushs gradient stops Gets or sets a BrushMappingMode enumeration that specifies whether the gradient brushs positioning coordinates are absolute or relative to the output area Gets or sets the type of spread method that specifies how to draw a gradient that starts or ends inside the bounds of the object to be painted Gets or sets the starting two-dimensional coordinates of the linear gradient
RadialGradientBrush
The RadialGradientBrush is similar to the LinearGradientBrush. The RadialGradientBrush also fills an area with a gradient fill. The difference lies on the way, the gradient is applied. The RadialGradientBrush fill the gradient which radiates out in a circular pattern starting from the center point. You can use the GradientOrigin property to identify the point where the first color in the gradient starts. The default value of the GradientOrigin is 0.5, which represents the middle of the fill region. The gradient radiates out from the point in the GradientOrigin which is the starting point in a circular manner. The RadialGradientBrush is a good choice for filling rounded shapes and creates lightening effect. You can add a RadialGradientBrush to your application by adding the following code:
<RadialGradientBrush> <!-- GradientStops --> </RadialGradientBrush>
The noteworthy properties of the RadialGradientBrush are listed in Table 1.12: Table 1.12: Property of RadialGradientBrush
Property
Center ColorInterpolationMode GradientOrigin GradientStops MappingMode
Description
Gets or sets the center of the outermost circle of the radial gradient Gets or sets a ColorInterpolationMode enumeration that specifies how the gradients colors are interpolated Gets or sets the location of the two-dimensional focal point that defines the beginning of the gradient Gets or sets the brushs gradient stops Gets or sets a BrushMappingMode enumeration that specifies whether the gradient brushs positioning coordinates are absolute or related to the output area
Property
RadiusX RadiusY SpreadMethod
Description
Gets or sets the horizontal radius of the outermost circle of the radial gradient Gets or sets the vertical radius of the outermost circle of a radial gradient Gets or sets the type of spread method that specifies how to draw a gradient that starts or ends inside the bounds of the object to be painted
DrawingBrush
The DrawingBrush paints an area with drawing object, which can include shapes, text, video, images, or other drawings. The DrawingBrush paints an area with a Drawing object. The Drawing object describes the visible content of the DrawingBrush. The DrawingBrush stretches the drawing to fill the output area. The drawing that is shown with the brush is defined using the GeometryDrawing element. You can also create a repeating pattern of the drawing by setting the Viewport and TileMode property of the DrawingBrush. You can apply the DrawingBrush to your application by adding the following code:
<DrawingBrush .../>
The noteworthy properties of the DrawingBrush class are listed in Table 1.13: Table 1.13: Property of DrawingBrush
Property
AlignmentX AlignmentY Drawing Stretch TileMode Viewbox ViewboxUnits Viewport ViewportUnits
Description
Gets or sets the horizontal alignment of content in the TileBrush base tile Gets or sets the vertical alignment of content in the TileBrush base tile Gets or sets the Drawing that describes the contents of the DrawingBrush Gets or sets a value that specifies how the content of the TileBrush stretches to fit its tiles Gets or sets a value that specifies how a TileBrush fills the area that you are painting if the base tile is smaller than the output area Gets or sets the position and dimensions of the content in a TileBrush tile Gets or sets a value that specifies whether the Viewbox value is related to the bounding box of the TileBrush contents or whether the value is absolute Gets or sets the position and dimensions of the base tile for a TileBrush Gets or sets a BrushMappingMode enumeration that specifies whether the value of the Viewport, which indicates the size and position of the TileBrush base tile, is relative to the size of the output area
ImageBrush
You can use the ImageBrush to load an image into a brush. You can load the most common image file types, including bmp, png, gif, and jpeg file. The ImageSource property is used to display the image used in the ImageBrush. The image used in the ImageSource property is stretched to fill the area. This is the default behavior. You can control this behavior by setting the Stretch property of TileBrush to Uniform or UniformToFill. This causes the image to preserve the aspect ratio of the image. You can create a repeating pattern of the image by setting the Viewport and TileMode property. You can add the ImageBrush to your application by adding the following code:
<ImageBrush .../>
Chapter 1
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Freezable System.Windows.Media.Animation.Animatable System.Windows.Media.Brush System.Windows.Media.TileBrush System.Windows.Media.ImageBrush
The noteworthy properties of the ImageBrush class are listed in Table 1.14: Table 1.14: Properties of ImageBrush
Property
AlignmentX AlignmentY ImageSource Stretch TileMode Viewbox ViewboxUnits Viewport ViewportUnits
Description
Gets or sets the horizontal alignment of content in the TileBrush base tile Gets or sets the vertical alignment of content in the TileBrush base tile Gets or sets the image displayed by the ImageBrush Gets or sets a value that specifies how the content of the TileBrush stretches to fit its tiles Gets or sets a value that specifies how a TileBrush fills the area that you are painting if the base tile is smaller than the output area Gets or sets the position and dimensions of the content in a TileBrush tile Gets or sets a value that specifies whether the Viewbox value is relative to the bounding box of the TileBrush contents or the value is absolute Gets or sets the position and dimensions of the base tile for a TileBrush Gets or sets a BrushMappingMode enumeration that specifies whether the value of the Viewport, which indicates the size and position of the TileBrush base tile, is relative to the size of the output area
VisualBrush
The VisualBrush paints an area with a visual. The VisualBrush allows you to take the visual content of an element and use it to fill the area. For example, you can copy the appearance of a button in the window to a region somewhere else in that window. By this way, you are using an existing image to create the duplicate image. Another way to specify the Visual content of the VisualBrush is to create a new Visual and use it to set the Visual property of the VisualBrush. With VisualBrush, you can also create effects such as reflection. You can also use the VisualBrush to display a video by setting the Visual property to MediaElement. You can add the VisualBrush to your application by adding the following code:
<VisualBrush .../>
The noteworthy properties of the VisualBrush are listed in Table 1.15: Table 1.15: Property of VisualBrush
Property
AlignmentX AlignmentY AutoLayoutContent Stretch TileMode Viewbox
Description
Gets or sets the horizontal alignment of content in the TileBrush base tile Gets or sets the vertical alignment of content in the TileBrush base tile Gets or sets a value that specifies whether the VisualBrush will place the content Gets or sets a value that specifies how the content of the TileBrush stretches to fit its tiles Gets or sets a value that specifies how a TileBrush fills the area that you are painting if the base tile is smaller than the output area Gets or sets the position and dimensions of the content in a TileBrush tile
10
Property
ViewboxUnits Viewport ViewportUnits
Description
Gets or sets a value that specifies whether the Viewbox value is relative to the bounding box of the TileBrush contents or whether the value is absolute Gets or sets the position and dimensions of the base tile for a TileBrush Gets or sets a BrushMappingMode enumeration that specifies whether the value of the Viewport, which indicates the size and position of the TileBrush base tile, is relative to the size of the output area Gets or sets the brushs content
Visual
The noteworthy properties of the Drawing class are listed in Table 1.16: Table 1.16: Properties of Drawing Class
Property
Bounds CanFreeze DependencyObjectType Dispatcher HasAnimatedProperties IsFrozen IsSealed
Description
Retrieves the axis-aligned bounds of the drawings contents Retrieves a value that indicates whether the object can be made unmodifiable Retrieves the DependencyObjectType that wraps the CLR type of Drawing class Retrieves the Dispatcher the Drawing class DispatcherObject is associated with Retrieves a value that indicates whether one or more AnimationClock objects is associated with any of the Drawing class dependency properties Retrieves a value that indicates whether the object is currently modifiable Retrieves a value that declares whether this instance is currently read-only
You can find the methods of Drawing class listed in Table 1.17: Table 1.17: Methods of Drawing Class
Method
Clone CloneCurrentValue
Description
Creates a modifiable clone of the Drawing class. Creates a modifiable clone of the current value of the Drawing class
The Drawing class helps you make a WPF application with the help of different types of drawing object and the DrawingContext class, which we describe next.
11
Chapter 1
The GeometryDrawing classEnables you to create shape with a fill and an outline by using the Pen and Brush property with the Geometry. The Geometry describes the structure of the shape, the Brush describes the fill color of the shape, and the Pen describes the outline. The ImageDrawing classEnables you to display an ImageSource with a DrawingBrush, DrawingImage, or Visual. The ImageSource property specifies the image to be drawn and the Rect property specifies the position and size of each image. The GlyphRunDrawing classRepresents the Drawing object that renders a GlyphRun. The GlyphRun contains font details such as glyph indices and the individual glyph positions. In simple words, to draw text, you use a GlyphRunDrawing and a GlyphRun. The VideoDrawing classEnables you to play a media file. You can use the VideoDrawing and the MediaPlayer to play an audio or a video file. You can load and play media in two ways. The first way is to use a MediaPlayer and the VideoDrawing by themselves. The second way is to create your own MediaTimeline to use with the MediaPlayer and VideoDrawing. The DrawingGroup classEnables you to combine a collection of drawings that can be operated as a single drawing. The flexibility of this class enables you to create complex scenes. The DrawingGroup also enables you to apply opacity masks, transforms, bitmap effects, and other operations to its content. The operations of DrawingGroup are applied in the following order: OpacityMask, Opacity, BitmapEffect, ClipGeometry, GuidelineSet, and then Transform.
Method
CheckAccess Close DrawDrawing DrawEllipse DrawGeometry DrawGlyphRun DrawImage DrawLine DrawRectangle DrawRoundedRectangle DrawText DrawVideo Equals GetHashCode GetType
Description
Determines whether the calling thread has access to this DispatcherObject Closes the DrawingContext and flushes the content Draws the specified Drawing object Draws an ellipse Draws the specified Geometry using the specified Brush and Pen Draws the specified text Draws an image into the region defined by the specified Rect Draws a line with the specified Pen Draws a rectangle Draws a rounded rectangle Draws formatted text at the specified location Draw a video into the specified region Determines whether the specified Object is equal to the current Object Serves as a hash function for a particular type Retrieves the Type of the current instance
12
Method
Pop PushClip PushEffect PushGuidelineSet PushOpacity PushOpacityMask PushTransform ToString VerifyAccess
Description
Pops the last opacity mask, opacity, clip, effect, or transform operation that was pushed onto the drawing context Pushes the specified clip region onto the drawing context Pushes the specified BitmapEffect onto the drawing context Pushes the specified GuidelineSet onto the drawing context Pushes the specified opacity setting onto the drawing context Pushes the specified opacity mask onto the drawing context Pushes the specified Transform onto the drawing context Returns a String that represents the current Object Enforces that the calling thread has access to this DispatcherObject
The DrawingContext class has one noteworthy property, the Dispatcher property, which retrieves the Dispatcher the DrawingContext class is associated with.
13
Chapter 1
<Ellipse Canvas.Left="151" Canvas.Top="67" Height="5" Name="ellipse5" Stroke="Black" Width="5" Fill="Black" /> <Rectangle Canvas.Left="105" Canvas.Top="129" Height="111" Name="rectangle1" Stroke="Black" Width="59" Fill="HotPink" /> <Ellipse Canvas.Left="127" Canvas.Top="128" Height="10" Name="ellipse6" Stroke="Black" Width="9" Fill="Blue" /> <Ellipse Canvas.Left="127" Canvas.Top="148" Height="10" Name="ellipse7" Stroke="Black" Width="9" Fill="Blue" /> <Ellipse Canvas.Left="127" Canvas.Top="168" Height="10" Name="ellipse8" Stroke="Black" Width="9" Fill="Blue" /> <Ellipse Canvas.Left="127" Canvas.Top="188" Height="10" Name="ellipse9" Stroke="Black" Width="9" Fill="Blue" /> <Ellipse Canvas.Left="127" Canvas.Top="208" Height="10" Name="ellipse10" Stroke="Black" Width="9" Fill="Blue" /> <Ellipse Canvas.Left="127" Canvas.Top="228" Height="10" Name="ellipse11" Stroke="Black" Width="9" Fill="Blue" /> <Line X1="12" X2="400" Y1="145" Y2="115" Stroke="Black" StrokeThickness="5" Height="158" Canvas.Left="131" Canvas.Top="114" Width="42" /> <Path Name="path1" Stroke="Black" Data="M 60,113 Q 90,146 111,111" StrokeThickness="5" Height="134" Canvas.Left="48" Canvas.Top="-14" Width="145" /> <Line X1="124" X2="145" Y1="145" Y2="166" Stroke="Black" StrokeThickness="5" Height="168" Canvas.Left="40" Canvas.Top="-7" Width="147" /> <Line X1="145" X2="600" Y1="149" Y2="166" Stroke="Black" StrokeThickness="5" Height="168" Canvas.Left="37" Canvas.Top="8" Width="178" /> <Line X1="124" X2="170" Y1="145" Y2="16" Stroke="Black" StrokeThickness="5" Height="115" Canvas.Left="-42" Canvas.Top="65" Width="147" /> <Line X1="115" X2="145" Y1="145" Y2="166" Stroke="Black" StrokeThickness="5" Height="168" Canvas.Left="-50" Canvas.Top="11" Width="147" /> <Polygon Points="10,110 60,10 110,110" Fill="Blue" Height="55" Canvas.Left="72" Canvas.Top="-7" Width="132" /> <Line X1="11" X2="145" Y1="145" Y2="166" Stroke="Black" StrokeThickness="5" Height="163" Canvas.Left="83" Canvas.Top="110" Width="41" /> <Line X1="145" X2="145" Y1="145" Y2="166" Stroke="Black" StrokeThickness="5" Height="168" Canvas.Left="-23" Canvas.Top="94" Width="151" /> <Line X1="145" X2="145" Y1="145" Y2="166" Stroke="Black" StrokeThickness="5" Height="168" Canvas.Left="-1" Canvas.Top="94" Width="147" /> <Line X1="11" X2="10" Y1="145" Y2="115" Stroke="Black" StrokeThickness="5" Height="158" Canvas.Left="121" Canvas.Top="-52" Width="42" /> <Polyline Points="10,110 6,10 110,110" Stroke="Black" StrokeThickness="4" Height="52" Canvas.Left="209" Canvas.Top="210" Width="50"/> <Ellipse Canvas.Left="172" Canvas.Top="118" Height="100" Name="ellipse12" Stroke="Black" Width="87"> <Ellipse.BitmapEffect> <OuterGlowBitmapEffect GlowColor="DarkViolet" /> </Ellipse.BitmapEffect> </Ellipse> </Canvas> </Window>
Adding the code to the application will create a human figure. You will notice that all the shapes are used in the application to create the figure. When you run the code, by pressing F5, you will get an output as shown in Figure 1.1:
14
In this code, two shapes are added and different Stretch properties are applied to both of them. The first shape has the Stretch property to Fill and the second shape has the Stretch property to Uniform. When you run the code, by pressing F5, you will get an output as shown in Figure 1.2:
Drawing Geometry
The Geometry class enables you to describe the geometry of a 2-D shape. The classes that derive from the Geometry class are EllipseGeometry, PathGeometry, and CombinedGeomtry. You can create simple shape using geometry or complex shape by combining two geometries. Lets create an application using Geometry. For this, create a WPF application named DrawingGeometry (available on the CD-ROM) and add the following code given in Listing 1.3 to Window1.xaml: Listing 1.3:Using the Geometry Class
<Window x:Class="DrawingGeometry.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300">
15
Chapter 1
<Grid> <Path Stroke="Black" StrokeThickness="1" Fill="LightPink"> <Path.Data> <GeometryGroup> <EllipseGeometry Center="75,70" RadiusX="60" RadiusY="40" /> <RectangleGeometry Rect="25,55 100 25" /> </GeometryGroup> </Path.Data> </Path> </Grid> </Window>
In this code, EllipseGeometry is used to create a circle and RectangleGeometry is used to create the rectangle. When you run the code by pressing F5, you will get an output as shown in Figure 1.3:
16
In this code, there are four types of CombinedGeometry applied on the EllipseGeometry. The CombinedGeometry works best on EllipseGeometry, therefore, it is used. When you run the code, by pressing F5, you will get an output as shown in Figure 1.4:
17
Chapter 1
Transforming Shapes
In WPF, you can transform the shapes using the RenderTransform, RotateTransform, and ScaleTransform properties. You have learned about these properties in Chapter 18, Working with Typography and Documents in WPF, where we applied transformation on text. Here, the transformation is applied to the shapes. The RenderTransform property affects the rendering position of the element. The RotateTransform property rotates the shape in the specified angle. The ScaleTransform property flips the shape either horizontally or vertically. Lets transform shapes by using these properties. For this, create a WPF application named TransformmingShapes (available in the CD) and add the following code given in Listing 1.5 to Window1.xaml: Listing 1.5: Applying Transformation
<Window x:Class="TransformmingShapes.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Canvas Opacity="1"> <Rectangle Canvas.Left="22" Canvas.Top="22" Height="91" Name="rectangle1" Stroke="Black" Width="73" Fill="BlueViolet" Opacity="1" > <Rectangle.RenderTransform> <RotateTransform Angle="50" CenterX="45" CenterY="45"/> </Rectangle.RenderTransform> </Rectangle> <Ellipse Canvas.Left="119" Canvas.Top="104" Height="91" Name="ellipse2" Stroke="Black" Width="90" Fill="CadetBlue"> <Ellipse.RenderTransform> <RotateTransform Angle="45" CenterX="100" CenterY="100"/> </Ellipse.RenderTransform> </Ellipse> <Rectangle Canvas.Left="96" Canvas.Top="203" Height="23" Name="button1" Width="75" Fill="Pink"> <Rectangle.RenderTransform> <ScaleTransform ScaleX="-1" /> </Rectangle.RenderTransform> </Rectangle> </Canvas> </Window>
In this code, we have added an ellipse and two rectangles on which we have applied the properties. When you run the code, by pressing F5, you get the output as shown in Figure 1.5:
18
GeometryGroup. There are two values of the FillRule property, EvenOdd and NonZero. If you specify the EvenOdd value, the alternate area will be filled. The NonZero value fills the whole area specified in the GeometryGroup or the PathGeometry with the specified color. The PathGeometry is made up of one or more figures which is represented by the PathFigure class. Each figure is made up of one or more segments which is defined by the PathSegment class. Lets use the Path shape and the PathGeometry to see the application of the FillRule property. For this, create a WPF application named UsingPath (available on the CD-ROM) and add the following code given in Listing 1.6 to Window1.xaml: Listing 1.6: Using Path Class
<Window x:Class="UsingPath.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Grid> <Path Stroke="Black" StrokeThickness="2" Fill="LightBlue"> <Path.Data> <GeometryGroup FillRule="EvenOdd"> <PathGeometry> <PathGeometry.Figures> <PathFigure StartPoint="150,150"> <PathFigure.Segments> <PathSegmentCollection> <ArcSegment Size="50,50" IsLargeArc="True" SweepDirection="CounterClockwise" Point="25,120" /> </PathSegmentCollection> </PathFigure.Segments> </PathFigure> <PathFigure StartPoint="150,150"> <PathFigure.Segments> <PathSegmentCollection> <ArcSegment Size="70,70" IsLargeArc="True" SweepDirection="CounterClockwise" Point="25,100" /> </PathSegmentCollection> </PathFigure.Segments> </PathFigure> </PathGeometry.Figures> </PathGeometry> </GeometryGroup> </Path.Data> </Path> </Grid> </Window>
In this code, the FillRule property of EvenOdd is applied on the PathGeometry and the GeometryGroup. There are two arcs added to the application which are filled with color using the FillRule property. The PathFigure class is used to represent a section of the geometry. When you run the code, by pressing F5, you get the output as shown in Figure 1.6:
19
Chapter 1
Using Brushes
In this section, you will learn about how to use the different brushes to give your WPF application a rich look. As you know, there are five types of brushes available in WPF such as LinearGradientBrush, RadialGradeintBrush, ImageBrush, DrawingBrush, and VisualBrush. You will see further the usage of the all the brushes in detail.
In this code, the shapes are colored using the LinearGradientBrush and the RadialGradientBrush. As you can see in the code, the colors in both the brushes are described using the GardientStop class. The difference is shown in the output of the brushes. When you run the code, by pressing F5, you get the output as shown in Figure 1.7:
20
ImageBrush
The ImageBrush paints an area with an image. The ImageSource property of the ImageBrush is used to paint the area. Lets add the ImageBrush to the application. For this, create a WPF application named ImageBrush (available on the CD-ROM) and add the following code given in Listing 1.8 to Window1.xaml: Listing 1.8: ImageBrush
<Window x:Class="ImageBrush.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300" xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="PresentationOptions"> <Grid> <StackPanel> <Rectangle Width="100" Height="100" Stroke="Red" StrokeThickness="4"> <Rectangle.Fill> <ImageBrush Stretch="UniformToFill" ImageSource="C:\Users\avantika\Documents\Visual Studio 2008\Projects\ImageBrush\Image.jpg" PresentationOptions:Freeze="True" /> </Rectangle.Fill> </Rectangle> <Rectangle Width="200" Height="100" Stroke="Black" StrokeThickness="2" Margin="50,50,20,20"> <Rectangle.Fill> <ImageBrush Stretch="Fill" ImageSource="C:\Users\avantika\Documents\Visual Studio 2008\Projects\ImageBrush\Image.jpg" PresentationOptions:Freeze="True" TileMode="Tile"/> </Rectangle.Fill> </Rectangle> </StackPanel> </Grid> </Window>
You need to change the path of the image file specified in this application as well as all the applications in this chapter that are using the image file according to the image location in your system.
In this code, images are added to the application in different views and mode. When you run the code, by pressing F5, you get the output as shown in Figure 1.8:
21
Chapter 1
22
In this code, DrawingBrush and VisualBrush are applied to the application. When you run the code by pressing F5, you get the output as shown in Figure 1.9:
23
Chapter 1
<Rectangle.Fill> <DrawingBrush TileMode="FlipXY" Viewport="0,0,0.5,0.5" Drawing="{StaticResource TileSize}" /> </Rectangle.Fill> </Rectangle> </StackPanel> </Page>
You can change the root element of the application to Page in a WPF application.
In this code, the DrawingBrush is used to create four rectangles and each is given a different TileMode setting. When you run code by pressing F5, you get the output as shown in Figure 1.10:
24
In the following code, the reflection of the image is created by using VisualBrush. When you run code by pressing F5, you get the output as shown in Figure 1.11:
25
Chapter 1
In this code, the same image is displayed in two different ways. In the first image, the Stretch property of the image is set to Uniform and thus preserving the aspect ratio of the image. In the second image, the Stretch property of the image is set to UniformToFill. When you run code by pressing F5, you get the output as shown in Figure 1.12:
3-D Graphics
WPF provides a set of 3-D graphics that integrate with 2-D graphics in order to create visually appealing layout, user interface, and data visualization. The 3-D implementation in WPF allows developers to draw, transform, and animate the 3-D graphics in both XAML and code. You can combine the 2-D and 3-D graphics to create rich controls and enhance the user experience of an application interface. The most important objects used in the creation of 3-D graphics in WPF are Viewport3D, Camera, Materials and Lights, which we will discuss next.
26
The noteworthy properties of the Viewport3D class are listed in Table 1.19: Table 1.19: Property of Viewport3D Class
Property
Camera Children
Description
Gets or sets a camera object that projects the 3-D contents of the Viewport3D to the 2-D surface of the Viewport3D Retrieves a collection of the Visual3D children of the Viewport3D
Cameras
The camera in WPF is an essential element for rendering 3-D Graphics. You need to place the camera at the correct position and adjust it in the correct direction before actually rendering a 3-D scene. You can do this by setting the Camera property of the Viewport3D class. The camera in WPF is represented by the System.Windows.Media.Media3D namespace. The Camera class represents an imaginary viewing position and direction in a 3-D coordinate space that describes how a 3-D model is projected on a 2-D visual. The inheritance hierarchy of the Camera class is as follows:
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Freezable System.Windows.Media.Animation.Animatable System.Windows.Media.Media3D.Camera
The noteworthy methods of the Camera class are listed in Table 1.20: Table 1.20: Methods of ProjectionCamera Class
Method
Clone CloneCurrentValue ToSring
Description
Creates a modifiable clone of this Camera class Creates a modifiable clone of this Camera object, making deep copies of this objects current values Creates a string representation of the Camera class
27
Chapter 1
The noteworthy property of the ProjectionCamera class is listed in Table 1.21: Table 1.21: Property of ProjectionCamera Class
Property
Transform
Description
Retrieves or sets the Transform3D applied to the camera
WPF includes three Camera classes as follows: PerspectiveCameraRenders the scene so that the object that are farther, appear smaller OrthographicCameraFlattens the 3-D objects so that the exact scale is preserved MatrixCameraSpecify a matrix that is used to transform the 3-D scene to a 2-D view Here, we are discussing the two important camera classes, i.e. PerspectiveCamera OrthographicCamera, in detail.
and
PerspectiveCamera Class
The PerspectiveCamera class represents a perspective projection camera. The PerspectiveCamera renders the scene so that the objects that are farther away appear smaller. The PerspectiveCamera class is derived from the ProjectionCamera base class. The PerspectiveCamera is the most versatile and the most commonly used camera in WPF. The PerspectiveCamera specifies the projection of a 3-D model object to a 2D visual surface. The object described using the PerspectiveCamera have their sides converge toward a point on the horizon. The objects that are closer to the Camera appear larger, and the objects farther from the Camera appear smaller. You can limit the range of camera projection by setting the NearPlaneDistance and FarPlaneDistance properties. The NearPlaneDistance property allows you to specify a minimum distance from the camera of the near clip plane. On the other hand, the FarPlaneDistance property allows you to specify a distance from the camera of the far clip plane, which ensures that objects too far away are not included in the scene. You can add a PerspectiveCamera to your application by adding the following code:
<PerspectiveCamera .../>
The noteworthy property of the PerscpectiveCamera class is listed in Table 1.22. Table 1.22: Property of PerspectiveCamera class
Property
FieldOfView
Description
Gets or sets a value that represents the cameras horizontal field of view
OrthographicCamera
The OrthographicCamera class represents an orthographic projection camera. The OrthographicCamera class specifies an orthogonal projection of a 3-D model to a 2-D visual surface. The OrthographicCamera specifies a position, viewing direction, and upward direction. The OrthographicCamera class describes a viewing box whose sides are parallel, instead of one whose sides meet in a point at the horizon like the PerspectiveCamera. The OrthographicCamera flattens the 3-D objects so that the exact scale is preserved, not matter where a shape is positioned. You can add an OrthographicCamera to your application by adding the following code:
<OrthographicCamera .../>
28
The noteworthy property of the OrthographicCamera class is listed in Table 1.23. Table 1.23: Property of OrthographicCamera class
Property
Width
Description
Gets or sets the width of the cameras viewing box, in world units
3-D Models
All 3-D modeling programs in WPF include basic primitives or mesh. A basic 3-D primitive is a collection of vertices that form a single 3-D entity. For example, a triangle defined by three vertices. The three points in a triangle is coplanar. You can build a more complex shape by using mesh. When you build a model in WPF, you begin by building a primitive or a mesh. After building the complex shape, you can use these primitives or mesh to create the required scene. You can take the example of the sphere in WPF, which is built out of smaller triangles. You can also take the example of the simple closed figure, triangle which is defined by three vertices. The ModelVisual3D class represents the visual that contains the 3-D models. This class provides services and properties that are common to all the visual objects. The entire scene of the visual is defined in a single ModelVisual3D class and contains the Model3DGroup. The Model3DGroup class allows the developer to apply transformations or animations to group the 3-D models as if they were a single model. The Model3D is the abstract base class that represents a generic 3-D object and provides functionality for the 3-D models. To build a typical 3-D scene, you need some objects to view and some objects that make up the scene graph that derive themselves from the Model3D class. The classes that derive themselves from the Model3D class and help in building the 3-D scene are GeometryModel3D class, and MeshGeometry3D class. The MeshGeometry3D class provides triangle primitive for building a 3-D shape or any geometry. The MeshGeometry3D allows the developer to specify the position and texture coordinate information by specifying the Positions property. Once you have properly configured MeshGeometry3D, you need to wrap it in a GeometryModel3D class. The modeling geometries in WPF are supported with the GeometryModel3D class. The GeometryModel3D objects are responsible for defining the objects and their materials. The GeometryModel3D has only three important properties, Geometry, Material, and BackMaterial. The Geometry property takes the MeshGeometry3D that defined the shape of your object. The Material property gets or sets the material of the GeometryModel3D. Similarly, the BackMaterial property also gets or sets the material to be applied to the back of the object. The Material and BackMaterial property defines the surface of the shape. The surface is important for two reasons; first, it defines the color of the object, and second, it defines how the material responds to light.
29
Chapter 1
The DiffuseMaterial classSpecifies that the brush will be applied to the model evenly. The DiffuseMaterial allows the application of a 2-D brush, like a SolidColorBrush to diffusely light a 3-D model. The DiffuseMaterial diffuses light evenly in all the directions. The SpecularMaterial classCreates a glossy and highlighted look. It reflects the light back directly like a mirror. The SpecularMaterial specifies that the brush will be applied to the models as if the model surface is hard which is capable of reflecting lights. You can set the degree to which the texture will reflect the light by specifying the SpecularPower property. The EmmissiveMaterial classCreates a glowing look by generating its own light. This light does not reflect off other objects in the scene. It allows you to specify the texture that will be applied as though the model is emitting light equal to the color of the brush. You can apply multiple Materials to the scene by using the MaterialGroup class. For example, you may choose to apply a complex texture to a mesh using the DiffuseMaterial, and also add a highlighting effect with the SpecularMaterial on the same mesh. MaterialGroup allows you to treat these Materials as a single texture.
Lights
After adding model and material to the scene, you need to add a light source to the scene to make it visible. The light effects in WPF are calculated for objects individually. The light that reflects from one object will not reflect off another object. In the same way, an object will not cast its shadow on another object, no matter where it is placed. Light class is the abstract base class for using light in WPF. WPF provides following four light classes for the implementation of light in WPF: The DirectionalLight classIlluminates light like a distant light source. The DirectionalLight lights the object that projects its effect along a direction specified by the Vector3D. The light specified by the DirectionalLight comes from one side and you can see the edges and shadow. You can take the example of Sunlight in context of DirectionalLight. The AmbientLight classProvides an unnatural light that lights the scene with scattered light. The AmbientLight lights the object uniformly regardless of the shape, location or orientation. The PointLight classRadiates light in all directions, beginning at a single point. The PointLight have a position and they point the light from that position. The objects in the scene are illuminated depending on their position and distance with respect to the light. The Range property of the PointLight determines the distance beyond which the models will not be illuminated by light. The SpotLight classRadiates light outward in a cone style starting from a single point. The SpotLight inherits from PointLight. The InnerConeAngle and OuterConeAngle property specify the area of the projection of the light in the cone shaped area.
30
In this code, we are actually creating a 3-D model by adding Viewport3D, Camera, Model, and Material. The output of the code is shown in Figure 1.13.
In this code, you are adding Material to the 3-D model which you have created in Listing 1.11. When you run the full code by pressing F5, you get the output as shown in Figure 1.13:
31
Chapter 1
32
In this code, a 3-D pattern is created. The Material on the 3-D model is added using the DrawingBrush. When you run the code by pressing F5, you get the output as shown in Figure 1.14:
Adding Cameras
The 3-D scene that you are creating is actually a 2-D representation of a 3-D object. The 3-D scene looks different depending upon the viewer angle of view. So, you must specify the angle of view. For this purpose, Camera is used in WPF to specify the point of view of the 3-D scene. There are three types of Camera available in WPF,
33
Chapter 1
MatrixCamera, OrthographicCamera and PerspectiveCamera. In this section, we will discuss about the two most important and most used camera in WPF: OrthographicCamera PerspectiveCamera
OrthographicCamera
The OrthographicCamera describes the points that are parallel to the angle of view, instead of the one whose sides meet in the point of Camera. Lets learn the usage of the OrthographicCamera. For this, create a WPF application named OrthographicCamera (available on the CD-ROM) and add the following code given in Listing 1.16 to Window1.xaml: Listing 1.16: Using OrthographicCamera
<Window x:Class="OrthographicCamera.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Grid> <Viewport3D> <Viewport3D.Camera> <OrthographicCamera LookDirection="7,-3,-4" UpDirection="1,1,100" Position="-5.5,2.5,3" /> </Viewport3D.Camera> <ModelVisual3D> <ModelVisual3D.Content> <Model3DGroup> <GeometryModel3D> <GeometryModel3D.Geometry> <MeshGeometry3D Positions="-1 -1 0 1 -1 0 -1 1 0 1 1 0" Normals="0 0 1 0 0 1 0 0 1 0 0 1" TextureCoordinates="1 0 1 1 0 0 1 0" TriangleIndices="0 1 2 1 3 2" /> </GeometryModel3D.Geometry> <GeometryModel3D.Material> <DiffuseMaterial> <DiffuseMaterial.Brush> <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5" Opacity="0.9"> <LinearGradientBrush.GradientStops> <GradientStop Color="Wheat" Offset="0.1" /> <GradientStop Color="Pink" Offset="0.75" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> </GeometryModel3D.Material> </GeometryModel3D> </Model3DGroup> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D> </Grid> </Window>
In this code, a solid figure is created which is viewed on the surface using the OrthographicCamera. When you run the code by pressing F5, you get the output as shown in Figure 1.15:
34
PerspectiveCamera
PerspectiveCamera specifies a projection that makes the scene short. The PerspectiveCamera describes the area whose sides converge toward a point on the horizon. Lets learn the usage of PerscpectiveCamera. For this, create a WPF application named PerspectiveCamera (available in the CD) and add the following code given in Listing 1.17 to Window1.xaml: Listing 1.17: Using PerspectiveCamera
<Window x:Class="PerspectiveCamera.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Grid> <Viewport3D> <Viewport3D.Camera> <PerspectiveCamera LookDirection="6,-3,-4" UpDirection="0,0,1" Position="-5,2.5,3" FieldOfView="30" /> </Viewport3D.Camera> <ModelVisual3D> <ModelVisual3D.Content> <Model3DGroup> <GeometryModel3D> <GeometryModel3D.Geometry> <MeshGeometry3D Positions="-1 -1 0 1 -1 0 -1 1 0 1 1 0" Normals="0 0 1 0 0 1 0 0 1 0 0 1" TextureCoordinates="1 0 1 1 0 0 1 0" TriangleIndices="0 1 2 1 3 2" /> </GeometryModel3D.Geometry> <GeometryModel3D.Material> <DiffuseMaterial> <DiffuseMaterial.Brush> <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5" Opacity="0.9"> <LinearGradientBrush.GradientStops> <GradientStop Color="Wheat" Offset="0.1" /> <GradientStop Color="Pink" Offset="0.75" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> </GeometryModel3D.Material> </GeometryModel3D> </Model3DGroup> </ModelVisual3D.Content>
35
Chapter 1
</ModelVisual3D> </Viewport3D> </Grid> </Window>
In this code, a solid figure is created which is viewed on the surface using the PerspectiveCamera. When you run the code by pressing F5, you get the output as shown in Figure 1.16:
At this point, you can see the difference between the OrthographicCamera and PerspectiveCamera. The same figure is created for both Camera; the only difference is the way of angle in which they are viewed.
Adding Lights
Lights in WPF make the graphic visible on the Window. As discussed earlier, there are four kinds of light available in WPF, such as AmbeintLight, DirectionalLight, PointLight, and SpotLight. All the four types of light create a variety of light and shadow effect in WPF. Lets add the different types of light to the WPF application. For this create a WPF application named AddingLight (available on the CD) and add the following code given in Listing 1.18 to Window1.xaml: Listing 1.18: Adding Light to the WPF application
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > <Canvas Width="421" Height="301"> <Viewport3D ClipToBounds="True" Width="100" Height="100" Canvas.Left="0" Canvas.Top="1"> <Viewport3D.Camera> <PerspectiveCamera Position="0,0,2" LookDirection="0,0,-1" FieldOfView="20" /> </Viewport3D.Camera> <Viewport3D.Children> <ModelVisual3D> <ModelVisual3D.Content> <DirectionalLight Color="White" Direction="-0.4,-0.7,-0.9" /> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D> <GeometryModel3D.Geometry> <MeshGeometry3D TriangleIndices="0,1,2 3,4,5 " Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 " TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 " Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " /> </GeometryModel3D.Geometry> <GeometryModel3D.Material>
36
37
Chapter 1
<GradientStop Color="Green" Offset="1" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> </MaterialGroup> </GeometryModel3D.Material> <GeometryModel3D.Transform> <RotateTransform3D> <RotateTransform3D.Rotation> <AxisAngleRotation3D Axis="0,3,0" Angle="20" /> </RotateTransform3D.Rotation> </RotateTransform3D> </GeometryModel3D.Transform> </GeometryModel3D> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D.Children> </Viewport3D> <Viewport3D ClipToBounds="True" Width="100" Height="100" Canvas.Right="100" Canvas.Bottom="1"> <Viewport3D.Camera> <PerspectiveCamera Position="0,0,2" LookDirection="0,0,-1" FieldOfView="20" /> </Viewport3D.Camera> <Viewport3D.Children> <ModelVisual3D> <ModelVisual3D.Content> <PointLight Color="Wheat" Position="0,1,1.5"/> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D> <GeometryModel3D.Geometry> <MeshGeometry3D TriangleIndices="0,1,2 3,4,5 " Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 " TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 " Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,-0.5,0.5 " /> </GeometryModel3D.Geometry> <GeometryModel3D.Material> <MaterialGroup> <DiffuseMaterial> <DiffuseMaterial.Brush> <SolidColorBrush Color="Bisque"/> </DiffuseMaterial.Brush> </DiffuseMaterial> </MaterialGroup> </GeometryModel3D.Material> <GeometryModel3D.Transform> <RotateTransform3D> <RotateTransform3D.Rotation> <AxisAngleRotation3D Axis="0,3,0" Angle="40" /> </RotateTransform3D.Rotation> </RotateTransform3D> </GeometryModel3D.Transform> </GeometryModel3D> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D.Children> </Viewport3D> <Viewport3D ClipToBounds="True" Width="100" Height="100" Canvas.Left="0" Canvas.Bottom="1">
38
In this code, the usage of the four types of light is shown. When you run the code by pressing F5, you get the output as shown in Figure 1.17:
39
Chapter 1
TranslateTransform3D
The TranslateTransfom3D moves all the points of the 3-D model in the direction of the offset vector which you specify with OffsetX, OffsetY, and OffsetZ. Lets create a 3-D model on which you can apply the TranslateTransform3D. For this, create a WPF application named TranslateTransform3D (available on the CD-ROM) and add the following code given in Listing 1.19 to Window1.xaml: Listing 1.19: Applying TranslateTransform3D
<Window x:Class="TranslateTransform3D.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <DockPanel> <Canvas Width="300" Height="300"> <Viewport3D ClipToBounds="True" Width="200" Height="200"> <Viewport3D.Camera> <PerspectiveCamera x:Name="myPerspectiveCamera" Position="0,0,2" LookDirection="0,0,-1" FieldOfView="60" /> </Viewport3D.Camera> <Viewport3D.Children> <ModelVisual3D> <ModelVisual3D.Content> <DirectionalLight Color="Pink" Direction="-0.612372,-0.5,0.612372" /> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D> <GeometryModel3D.Geometry> <MeshGeometry3D TriangleIndices="0,1,2 3,4,5 " Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 " TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 " Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " /> </GeometryModel3D.Geometry> <GeometryModel3D.Material>
40
In this code, the 3-D model is moved according to the OffsetX, OffsetY, and OffsetZ properties of the TranslateTransform. When you run the code by pressing F5, you get the output as shown in Figure 1.18:
ScaleTransform3D
The ScaleTransform3D scales the 3-D model by a specified vector with reference to the center point. You can specify the same value in ScaleX, ScaleY, and ScaleZ properties, so that the 3-D model scales by the same value in the X, Y, and Z axis. Lets create a 3-D model on which you can apply ScaleTransfom3D. For this, create a WPF application named ScaleTransform3D (available on the CD-ROM) and add the following code given in Listing 1.20 to Window1.xaml: Listing 1.20: Applying ScaleTransform3D
<Window x:Class="ScaleTransform3D.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <DockPanel> <Canvas Width="321" Height="201"> <Viewport3D Width="150" Height="150" Canvas.Left="0" Canvas.Top="10"> <Viewport3D.Camera> <PerspectiveCamera Position="0,0,2" LookDirection="0,0,-1" FieldOfView="60" /> </Viewport3D.Camera> <Viewport3D.Children> <ModelVisual3D>
41
Chapter 1
<ModelVisual3D.Content> <DirectionalLight Color="White" Direction="-0.612372,0.5,-0.612372" /> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D> <GeometryModel3D.Geometry> <MeshGeometry3D TriangleIndices="0,1,2 3,4,5 " Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 " TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 " Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " /> </GeometryModel3D.Geometry> <GeometryModel3D.Material> <MaterialGroup> <DiffuseMaterial> <DiffuseMaterial.Brush> <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5"> <LinearGradientBrush.GradientStops> <GradientStop Color="Yellow" Offset="0.25" /> <GradientStop Color="Red" Offset="0.75" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> </MaterialGroup> </GeometryModel3D.Material> <GeometryModel3D.Transform> <ScaleTransform3D ScaleX="1" ScaleY="1.5" ScaleZ="1.5" CenterX="1" CenterY="1" CenterZ="1" /> </GeometryModel3D.Transform> </GeometryModel3D> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D.Children> </Viewport3D> </Canvas> </DockPanel> </Window>
In this code, the 3-D model is sized according to the ScaleX, ScaleY, and ScaleZ property of the ScaleTransform3D. When you run the code by pressing F5, you get the output as shown in Figure 1.19:
42
RotateTransform3D
You can rotate a 3-D model in different ways using RotateTransfom3D. A typical rotation is the one in which you specify an axis and an angle of rotation around the axis. The rotation is defined using the Rotation property. The axis angle of the rotation is defined using the Axis and Angle property. Lets create a 3-D model on which you can apply the RotateTransfom3D. For this, create a WPF application named RotateTransform3D (available on the CD-ROM) and add the following code given in Listing 1.21 to Window1.xaml: Listing 1.21: Applying RotateTransfom3D
<Window x:Class="RotateTransform3D.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <DockPanel> <Canvas Width="321" Height="201"> <Viewport3D Width="150" Height="150" Canvas.Left="0" Canvas.Top="10"> <Viewport3D.Camera> <PerspectiveCamera x:Name="myPerspectiveCamera" Position="0,0,2" LookDirection="0,0,-1" FieldOfView="60" /> </Viewport3D.Camera> <Viewport3D.Children> <ModelVisual3D> <ModelVisual3D.Content> <DirectionalLight Color="White" Direction="-0.612372,0.5,-0.612372" /> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <DirectionalLight Color="White" Direction="0.612372,-0.5,0.612372" /> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D> <GeometryModel3D.Geometry> <MeshGeometry3D TriangleIndices="0,1,2 3,4,5 " Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 " TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 " Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " /> </GeometryModel3D.Geometry> <GeometryModel3D.Material> <MaterialGroup> <DiffuseMaterial> <DiffuseMaterial.Brush> <RadialGradientBrush> <RadialGradientBrush.GradientStops> <GradientStop Color="Yellow" Offset="0" /> <GradientStop Color="Red" Offset="0.25" /> <GradientStop Color="Blue" Offset="0.75" /> <GradientStop Color="LimeGreen" Offset="1" /> </RadialGradientBrush.GradientStops> </RadialGradientBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> </MaterialGroup> </GeometryModel3D.Material> <GeometryModel3D.Transform> <RotateTransform3D> <RotateTransform3D.Rotation> <AxisAngleRotation3D Axis="0,2,1" Angle="45" />
43
Chapter 1
</RotateTransform3D.Rotation> </RotateTransform3D> </GeometryModel3D.Transform> </GeometryModel3D> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D.Children> </Viewport3D> </Canvas> </DockPanel> </Window>
In this code, the 3-D model is rotated by specifying the Axis and Angle properties of the RotateTransform3D. When you run the code by pressing F5, you get the output as shown in Figure 1.20:
44
Types of Animation
As stated earlier, animations generate property values, different animation types exist for different property types. For example, to animate a property that takes a Double, such as the Width property of the element, you use an animation that produces Double value. Since there are number of different property types, there are several animation classes in the System.Windows.Media.Animation namespace. All of them follow a strict naming convention and thus can be categorized in three parts, as follows: Basic Animation KeyFrame Animation Path Animation Lets discuss these in detail.
Basic Animation
The Basic animation in WPF creates a transition between two target values. The Basic animation animates between a starting and destination value or by adding an offset value to its starting value. The From property of the animation defines the starting point of the animation. The ending value is defined by setting the To property of the animation. The By property of the animation specifies an offset value. You can use the From, To, and By properties which can be used together or separately to determine an animation target value. The resulting behavior of the From, To, and By properties are listed in Table 1.24: Table 1.24: Resulting Behavior of the properties
Property
From From and To From and By To By
Resulting Behavior
The animation progresses from the value specified by the From property to the base value of the property being animated or to a previous animations output value These two properties are used together for the animation to progress from the value specified by the From property to the value specified by the To property These two properties are used together for the animation to progress from the value specified by the From property to the value specified by the sum of the From and By properties The animation progresses from the animated propertys base value or a previous animations output value to the value specified by the To property The animation progresses from the base value of the property being animated or a previous animations output value to the sum of that value and the value specified by the By property
You should not set the To and By property in the same animation.
KeyFrame Animation
The KeyFrame animations are a better choice in animations in comparison to the Basic animation. In the KeyFrame animation, you can specify any number of target values. The KeyFrame animation animates the value of the target property. A KeyFrame animation target value is described using KeyFrame objects. To specify the animation target value, you need to create KeyFrame objects and add them to the animation KeyFrame collection. For specifying animation with KeyFrame animation, you need to follow a particular sequence: You declare an animation and specify its Duration. For each target value, you need to create a KeyFrame of the appropriate type, set its value and KeyTime, and add it to the KeyFrame collection. To complete the animation process, associate the animation with a property like the Basic animation. There are different KeyFrame animation classes for different property type which are listed in Table 1.25:
45
Chapter 1
Property Type
Boolean Byte Color Decimal Double Int16 Int32 Int64 Matrix Object Point Quaternion Rect Rotation3D Single String Size Thickness Vector3D Vector
Animation Classes
BooleanAnimationUsingKeyFrames ByteAnimationUsingKeyFrames ColorAnimationUsingKeyFrames DecimalAnimationUsingKeyFrames DoubleAnimationUsingKeyFrames Int16AnimationUsingKeyFrames Int32AnimationUsingKeyFrames Int64AnimationUsingKeyFrames MatrixAnimationUsingKeyFrames ObjectAnimationUsingKeyFrames PointAnimationUsingKeyFrames QuaternionAnimationUsingKeyFrames RectAnimationUsingKeyFrames Rotation3DAnimationUsingKeyFrames SingleAnimationUsingKeyFrames StringAnimationUsingKeyFrames SizeAnimationUsingKeyFrames ThicknessAnimationUsingKeyFrames Vector3DAnimationUsingKeyFrames VectorAnimationUsingKeyFrames
The basic purpose of KeyFrame animation is to specify the KeyTime and Value property. The Value property specifies the target value for the KeyFrame. The KeyTime property specifies when the KeyFrame Value property is achieved. When the KeyFrame animation begins, it iterates through its key frames in the order defined by their KeyTime properties. If there is no KeyFrame at time 0, the animation creates a transition between the current value of target property and the Value of the first KeyFrame.
If you set the animation Duration to Automatic or equal to the time of the last KeyFrame, the animation ends.
Path Animation
A Path base animation modifies a value to correspond with the shape that is described by a PathGeometry object. It is primarily useful for moving an element along a Path. Path animation can be used to modify any property that has the right data type. Path animation is most useful when animating position related properties. When you create a Path based animation, you do not supply the starting and ending values, but the PathGeometry. The collection of lines and curves that constitute the Path determines the value that will be used for the animated property.
A Path based animation, always runs at a continuous speed. The total length of the Path and the duration that you have specified, determines the speed.
Animation Classes
You have learned about the different types of animation in WPF, such as Basic animation, KeyFrame animation, and Path animation. Although, WPF uses these three types of animations currently, you can create more animation classes that modify values using a completely different approach. These different types of animation
46
are contained in the System.Windows.Media.Animation namespace. Speaking in the broader sense, there are actually two kinds of animation: Those that vary a property incrementally between the staring and finishing values. Those that abruptly change a property from one value to another. The different types of animation classes available in the System.Windows.Media.Animation namespace are listed in Table 1.26: Table 1.26: Classes of System.Windows.Media.Animation namespace
Class
Animatable AnimationClock AnimationException AnimationTimeline BeginStoryboard BooleanAnimationUsingKeyFrames BooleanKeyFrame BooleanKeyFrameCollection ByteAnimation ByteAnimationUsingKeyFrames ByteKeyFrame ByteKeyFrameCollection CharAnimationUsingKeyFrames CharKeyFrame CharKeyFrameCollection Clock ClockCollection ClockController ColorAnimation ColorAnimationBase ColorAnimationUsingKeyFrames ColorKeyFrame ColorKeyFrameCollection ControllableStoryboardAction DecimalAnimation DecimalAnimationBase DecimalAnimationUsingKeyFrames
Description
Provides animation support Maintains the run-time state of an AnimationTimeline and processes its output values Thrown when an error occurs while animating a property Defines a segment of time over which output values are produced Begins a Storyboard and distributes its animations to their targeted objects and properties Animates the value of a property that takes a Boolean along a set of KeyFrames over a specified Duration Defines a segment with its own target value and interpolation method for a BooleanAnimationUsingKeyFrames Represents a collection of BooleanKeyFrame objects Animates the value of a Byte property between two target values using linear interpolation over a specified Duration Animates the value of a Byte property along a set of KeyFrames Defines an animation segment with its own target value and interpolation method for a ByteAnimationUsingKeyFrames Represents a collection of ByteKeyFrame objects Animates the value of a Char property along a set of KeyFrames over a specified Duration Defines an animation segment with its own target value and interpolation method for a CharAnimationUsingKeyFrames Represents a collection of CharKeyFrame objects Maintains run-time timing state for a Timeline Represents an ordered collection of Clock objects Interactively controls a Clock Animates the value of a Color property between two target values using linear interpolation over a specified Duration Animates a Color value Animates the value of a Color property along a set of KeyFrames over a specified Duration Defines an animation segment with its own target value and interpolation method for a ColorAnimationUsingKeyFrames Represents a collection of ColorKeyFrame objects Manipulates a Storyboard that has been applied by a BeginStoryboard action Animates the value of a Decimal property between two target values using linear interpolation over a specified Duration Animates a Decimal value Animates the value of a Decimal property along a set of KeyFrames
47
Chapter 1
Class
DecimalKeyFrame DecimalKeyFrameCollection DiscreteBooleanKeyFrame DiscreteByteKeyFrame DiscreteCharKeyFrame DiscreteColorKeyFrame DiscreteDecimalKeyFrame DiscreteDoubleKeyFrame DiscreteInt16KeyFrame DiscreteInt32KeyFrame DiscreteInt64KeyFrame DiscreteMatrixKeyFrame DiscreteObjectKeyFrame DiscretePoint3DKeyFrame DiscretePointKeyFrame DiscreteQuaternionKeyFrame DiscreteRectKeyFrame DiscreteRotation3DKeyFrame DiscreteSingleKeyFrame DiscreteSizeKeyFrame DiscreteStringKeyFrame DiscreteThicknessKeyFrame DiscreteVector3DKeyFrame DiscreteVectorKeyFrame
Description
Defines an animation segment with its own target value and interpolation method for a DecimalAnimationUsingKeyFrames Represents a collection of DecimalKeyFrame objects Animates from the Boolean value of the previous key frame to its own Value using discrete interpolation Animates from the Byte value of the previous key frame to its own Value using discrete interpolation Animates from the Char value of the previous key frame to its own Value using discrete interpolation Animates from the Color value of the previous key frame to its own Value using discrete interpolation Animates from the Decimal value of the previous key frame to its own Value using discrete interpolation Animates from the Decimal value of the previous key frame to its own Value using discrete interpolation Animates from the Int16 value of the previous key frame to its own Value using discrete interpolation Animates from the Int32 value of the previous key frame to its own Value using discrete interpolation Animates from the Int64 value of the previous key frame to its own Value using discrete interpolation Animates from the Matrix value of the previous key frame to its own Value using discrete interpolation Animates from the Object value of the previous key frame to its own Value using discrete interpolation Animates from the Point3D value of the previous key frame to its own Value using discrete interpolation Animates from the Point value of the previous key frame to its own Value using discrete interpolation Animates from the Quaternion value of the previous key frame to its own Value using discrete interpolation Animates from the Rect value of the previous key frame to its own Value using discrete interpolation Animates from the Rotation3D value of the previous key frame to its own Value using discrete interpolation Animates from the Single value of the previous key frame to its own Value using discrete interpolation Animates from the Size value of the previous key frame to its own Value using discrete interpolation Animates from the String value of the previous key frame to its own Value using discrete interpolation Animates from the Thickness value of the previous key frame to its own Value using discrete interpolation Animates from the Vector3D value of the previous key frame to its own Value using discrete interpolation Animates from the Vector value of the previous key frame to its own Value using discrete interpolation
48
Class
DoubleAnimation DoubleAnimationBase DoubleAnimationUsingKeyFrames DoubleAnimationUsingPath DoubleKeyFrame DoubleKeyFrameCollection KeySpline ParallelTimeline PauseStoryboard PointAnimation RectAnimation RemoveStoryboard RepeatBehaviorConverter ResumeStoryboard SeekStoryboard SetStoryboardSpeedRatio SingleAnimation SizeAnimation SkipStoryboardToFill StopStoryboard Storyboard ThicknessAnimation Timeline TimelineCollection TimelineGroup
Description
Animates the value of a Double property between two target values using linear interpolation over a specified Duration Animates a Double value Animates the value of a Double property along a set of KeyFrames Animates the value of a Double property between two or more target values using a PathGeometry to specify those values Defines an animation segment with its own target value and interpolation method for a DoubleAnimationUsingKeyFrames Represents a collection of DoubleKeyFrame objects Used by a spline key frame to define animation progress Defines a segment of time that may contain child Timeline objects Pauses a Storyboard Animates the value of a Point property between two target values using linear interpolation over a specified Duration Animates the value of a Rect property between two target values using linear interpolation Removes a Storyboard Converts instances of RepeatBehavior to and from other data types Resumes a paused Storyboard Provides functionality for seeking a specified time within the active period of a Storyboard Changes the speed of a Storyboard Animates the value of a Single property between two target values using linear interpolation over a specified Duration Animates the value of a Size property between two target values using linear interpolation over a specified Duration Advances a Storyboard to the end of its fill period Stops a Storyboard Provides object and property targeting information for its child animations Animates the value of a Thickness property between two target values using linear interpolation over a specified Duration Defines a segment of time Represents a collection of Timeline objects Represents a Timeline that may contain a collection of child Timeline objects
Essentials of Animation
In the preceding section, you learned about the different types of animation available in WPF and the different animation classes. In order to create the animation in WPF application, there are some essentials of animation that you should keep in mind. These essential include the Timeline class, the Storyboard class, the EventTrigger, and the KeyFrames. We will discuss these essentials next.
Animation Timeline
A timeline represents a stretch of time. It usually describes one or more events that happen during that stretch of time. Timelines of all kinds have a start time and duration. It provides the properties that enable you to specify the length of the segment, when it should start, how many times it should repeat, and how fast the time
49
Chapter 1
progresses in the segment. The timeline in animation is represented by the Timeline class. There are different types of specialized timelines are: AnimationTimeline classGenerates output values based on the timimg progress. It defines a segment of time over which the output value are produced. The values are used to animate the target property. MediaTimeline classA Timeline object which provides control over media timing in the same way that animation timeline objects control animations. For example, you can specify the Duration and BeginTime properties to specify when the media begins and how long it plays. ParallelTimeline classRepresents a segment of time that contains other child Timeline objects. These child elements are active according to their respective BeginTime properties. You can also make the child elements run in parallel with each other. The ParallelTimeline has its own BeginTime property, and so all child timeline BeginTime values are relative to the parent ParallelTimeline value for BeginTime. StoryboardA special type of ParallelTimeline that provides object and property targeting information for the timelines it contains. A Storyboard can contain any type of Timeline, including other container Timelines and animation. The noteworthy properties of the Timeline class are listed in Table 1.27: Table 1.27: Properties of Timeline class
Property
AccelerationRatio AutoReverse BeginTime CanFreeze DecelerationRatio DependencyObjectType Dispatcher Duration FillBehavior HasAnimatedProperties IsFrozen IsSealed Name RepeatBehavior SpeedRatio DesiredFrameRate
Description
Gets or sets a value specifying the percentage of the timelines Duration spent accelerating the passage of time from zero to its maximum rate Gets or sets a value that indicates whether the timeline plays in reverse after it completes a forward iteration Gets or sets the time at which the Timeline should begin Retrieves a value that indicates whether the object can be made unmodifiable Gets or sets a value specifying the percentage of the timelines Duration spent decelerating the passage of time from its maximum rate to zero Retrieves the DependencyObjectType that wraps the CLR type of Timeline class Retrieves the Dispatcher the Timeline class DispatcherObject is associated with Gets or sets the length of time for which the timeline plays, not counting repetitions Gets or sets a value that specifies how the Timeline behaves after it reaches at the end of its active period Retrieves a value that indicates whether one or more AnimationClock objects is associated with any of this objects dependency properties Retrieves a value that indicates whether the object is currently modifiable Retrieves a value that declares whether the Timeline class is currently read-only Gets or sets the name of the Timeline Gets or sets the repeating behavior of the timeline Gets or sets the rate, relative to its parent, at which time progresses for the Timeline Gets or sets the desired frame rate for the timeline and its child timelines
The noteworthy methods of the Timeline class are listed in Table 1.28: Table 1.28: Methods of Timeline class
Method
Clone CloneCurrentValue CreateClock
Description
Creates a modifiable clone of the Timeline, making copies of the object values Creates a modifiable clone of the Timeline object, making copies of the object current values Creates a Clock from the Timeline
50
Method
GetDesiredFrameRate SetDesiredFrameRate
Description
Retrieves the desired frame rate of the specified Timeline Sets the desired frame rate of the specified Timeline
Animation Storyboard
A Storyboard is an enhanced Timeline. You can use a Storyboard to group multiple animations, and it has the capabilities to control the playback of the animation, such as pausing it, stopping it, and also changing its position. The most basic feature provided by the Storyboard class is its ability to point to a specific property and a specific element using the TargetName and TargetProperty property. Thus, you can say that the Storyboard bridges the gap between your animation and the property you want to animate. A controllable Storyboard can pause, resume, stop, seek, and also be removed in the animation. To make a Storyboard controllable in XAML code, you specify the Name property of the BeginStoryboard object that creates it. You can also make a Storyboard controllable in code, by using the appropriate overload of the Storyboard Begin method and specify True to make it controllable. You can add a Storyboard, by adding the following code in your application:
<Storyboard> <!-- Children --> </Storyboard>
The properties of the Storyboard class is same as the Timeline class. The noteworthy property of the Storyboard class which is different from the Timeline class is listed in Table 1.29: Table 1.29: Property of Storyboard Class
Property
SlipBehavior
Description
Gets or sets a value that specifies how this timeline will behave when one or more of its Timeline children slips
The noteworthy methods of the Storyboard class are listed in Table 1.30: Table 1.30: Methods of Storyboard Class
Method
Begin Clone GetCurrentGlobalSpeed GetCurrentIteration GetCurrentProgress GetCurrentState GetCurrentTime GetIsPaused Pause Resume
Description
Initiates the set of animations associated with the Storyboard Creates a modifiable clone of the Storyboard Retrieves the CurrentGlobalSpeed of the clock that was created for the Storyboard Retrieves the CurrentIteration of the Clock that was created for the Storyboard Retrieves the CurrentProgress of the Clock that was created for the Storyboard Retrieves the CurrentState of the Clock that was created for the Storyboard Retrieves the CurrentTime of the Clock that was created for the Storyboard Retrieves a value that indicates whether the Clock that was created for the Storyboard is paused Pauses the clock that was created for the Storyboard Resumes the animation clock, or runtime-state, associated with the Storyboard instance
51
Chapter 1
Method
Seek SeekAlignedToLastTick SetSpeedRatio Stop
Description
Seeks the Storyboard to a new position when the next clock tick occurs Seeks the Storyboard to a new position immediately Sets the interactive speed ratio for the Clock that was created for the Storyboard Halts the Clock that was created for the Storyboard
If you are using code to add a Storyboard to the application, you must create a NameScope for the FrameworkElement and register the names of the objects to animate with that FrameworkElement. To enable the targeting of the FrameworkElement in XAML, you set its Name property. In the code-behind file of your application, you need to use the RegisterName method to register the element name with the element for which you have created a NameScope. You can interactively control a Storyboard after it has started. Table 1.31 lists a list of Storyboard actions that you use with event triggers to control a Storyboard: Table 1.31: Controllable Storyboard Actions
Action
BeginStoryboard PauseStoryboard ResumeStoryboard SetStoryboardSpeedRatio SkipStoryboardToFill StopStoryboard RemoveStotyboard
Effect
Starts the Storyboard Pauses the Storyboard Resumes a paused Storyboard Changes the Storyboard speed Advances the Storyboard to the end of its fill period Stops the Storyboard Removes the Storyboard
Key Frames
You can attach different KeyFrame with each animation and the subsequent interpolation method. The interpolation method describes the transition of animation between values over the duration of the animation. You can define the interpolation method for each KeyFrame segment by selecting the KeyFrame type with your animation. There are three different types of interpolation method, such as linear, discrete, and splined, described as follows: You can choose linear interpolation when you want your animation to progress at a constant rate of the segment duration. You can choose discrete interpolation when you want your animation to jump from one value to the next without interpolation.
52
You can use splined interpolation when you want your animation to achieve more realistic timing effect. You can use splined interpolation with spline KeyFrame. You need to specify KeySpline with the spline KeyFrame to implement splined interpolation. You can also use KeyFrame with different interpolation types in a single KeyFrame animation. When you apply two KeyFrame animations with different interpolations, the interpolation method of the second KeyFrame is used to create the transition from the first value to the second. The KeyFrame animation also uses the Duration property. You also need to specify what portion of the duration is given to each KeyFrame by specifying the KeyTime for each KeyFrame. You can set the value of KeyTime to any of the following values: UniformDivides the allotted time of the animation evenly between KeyFrame. PacedCreates a timing behavior resulting in an animation that interpolates at a constant rate. This means that the available time is allocated according to the length of each KeyFrame to determine the duration of each frame. TimeSpanSpecifies the value of KeyTime. The value of the TimeSpan should be greater than or equal to zero and less than or equal to the duration of animation. PercentagevEnds the KeyFrame at some percentage of the animation Duration. The value of Percentage must be greater than or equal to zero and less than or equal to 100 percent.
53
Chapter 1
<Rectangle Canvas.Left="105" Canvas.Top="129" Height="111" Name="rectangle1" Stroke="Black" Width="59" Fill="HotPink" /> <Ellipse Canvas.Left="127" Canvas.Top="128" Height="10" Name="ellipse6" Stroke="Black" Width="9" Fill="Blue" /> <Ellipse Canvas.Left="127" Canvas.Top="148" Height="10" Name="ellipse7" Stroke="Black" Width="9" Fill="Blue" /> <Ellipse Canvas.Left="127" Canvas.Top="168" Height="10" Name="ellipse8" Stroke="Black" Width="9" Fill="Blue" /> <Ellipse Canvas.Left="127" Canvas.Top="188" Height="10" Name="ellipse9" Stroke="Black" Width="9" Fill="Blue" /> <Ellipse Canvas.Left="127" Canvas.Top="208" Height="10" Name="ellipse10" Stroke="Black" Width="9" Fill="Blue" /> <Ellipse Canvas.Left="127" Canvas.Top="228" Height="10" Name="ellipse11" Stroke="Black" Width="9" Fill="Blue" /> <Line X1="12" X2="400" Y1="145" Y2="115" Stroke="Black" StrokeThickness="5" Height="158" Canvas.Left="131" Canvas.Top="114" Width="42" /> <Path Name="path1" Stroke="Black" Data="M 60,113 Q 90,146 111,111" StrokeThickness="5" Height="134" Canvas.Left="48" Canvas.Top="-14" Width="145" /> <Line X1="124" X2="145" Y1="145" Y2="166" Stroke="Black" StrokeThickness="5" Height="168" Canvas.Left="40" Canvas.Top="-7" Width="147" /> <Line X1="145" X2="600" Y1="149" Y2="166" Stroke="Black" StrokeThickness="5" Height="168" Canvas.Left="37" Canvas.Top="8" Width="178" /> <Line X1="124" X2="170" Y1="145" Y2="16" Stroke="Black" StrokeThickness="5" Height="115" Canvas.Left="-42" Canvas.Top="65" Width="147" /> <Line X1="115" X2="145" Y1="145" Y2="166" Stroke="Black" StrokeThickness="5" Height="168" Canvas.Left="-50" Canvas.Top="11" Width="147" /> <Polygon Points="10,110 60,10 110,110" Fill="Blue" Height="55" Canvas.Left="72" Canvas.Top="-7" Width="132" /> <Line X1="11" X2="145" Y1="145" Y2="166" Stroke="Black" StrokeThickness="5" Height="163" Canvas.Left="83" Canvas.Top="110" Width="41" /> <Line X1="145" X2="145" Y1="145" Y2="166" Stroke="Black" StrokeThickness="5" Height="168" Canvas.Left="-23" Canvas.Top="94" Width="151" /> <Line X1="145" X2="145" Y1="145" Y2="166" Stroke="Black" StrokeThickness="5" Height="168" Canvas.Left="-1" Canvas.Top="94" Width="147" /> <Line X1="11" X2="10" Y1="145" Y2="115" Stroke="Black" StrokeThickness="5" Height="158" Canvas.Left="121" Canvas.Top="-52" Width="42" /> <Polyline Name="Base" Points="10,110 6,10 110,110" Stroke="Black" StrokeThickness="4" Height="52" Canvas.Left="209" Canvas.Top="210" Width="50"/> <Ellipse Canvas.Left="172" Canvas.Top="118" Height="100" Name="Ball" Stroke="Black" Width="87"> <Ellipse.BitmapEffect> <OuterGlowBitmapEffect GlowColor="DarkViolet" /> </Ellipse.BitmapEffect> </Ellipse> <Button Canvas.Left="235" Canvas.Top="12" Height="23" Name="StartAnimation" Width="75">Start</Button> <Button Canvas.Left="235" Canvas.Top="45" Height="23" Name="StopAnimation" Width="75">Stop</Button> </Canvas> </Grid> <DockPanel.Triggers> <EventTrigger RoutedEvent="Button.Click" SourceName="StartAnimation"> <BeginStoryboard Name="StartMoveBall"> <Storyboard Name="MoveBall"> <DoubleAnimation RepeatBehavior="Forever" AccelerationRatio="0.4" DecelerationRatio="0.4" AutoReverse="True" By="100" Duration="0:0:3" Storyboard.TargetName="Ball" Storyboard.TargetProperty="(Canvas.Left)"/> </Storyboard> </BeginStoryboard>
54
In this code, we have used the figure created in Listing 1.1. We have added two buttons to the application and added Event Trigger to the Button. On the click of the Start Button the animation starts and the circle along with the figure starts moving. The AutoReverse property is set to True in the application. So, when the circle reaches at the end of the Window, it moves back again. The animation continues until you click the Stop Button. Once you click the Stop Button, the figure stops moving and comes back to its original place. When you run the code by pressing F5, you get the output as shown in Figure 1.21:
Using Triggers
The most common way to start an animation in WPF is to use EventTrigger. However, you can use the different types of trigger available in WPF to create an animation. For example, you can use PropertyTrigger to create animations in WPF. Lets create animations in WPF using trigger. For this, create a WPF application named UsingTrigger (available on the CD-ROM) and add the following code given in Listing 1.23 to Window1.xaml: Listing 1.23: Creating Trigger
<Window x:Class="UsingTrigger.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Window.Resources> <Style x:Key="PropertyTrigger" TargetType="{x:Type Button}"> <Setter Property="Opacity" Value="0.5"> </Setter> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Trigger.EnterActions> <BeginStoryboard> <Storyboard>
55
Chapter 1
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:1"/> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> <Trigger.ExitActions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.5" Duration="0:0:1"/> </Storyboard> </BeginStoryboard> </Trigger.ExitActions> </Trigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel> <Button Style="{StaticResource PropertyTrigger}"> Move the Mouse over me to Start Animation </Button> </StackPanel> </Window>
In this code, a Button is added to Window on which the animation is applied with the help of trigger. The Button is initially blurred with the help of the Opacity property. When you run the application, by pressing F5, a blurred Button on the Window is visible to you. When you move the mouse over the Button, it becomes visible, and when you remove the mouse, the Button again becomes blurred. You can see the output when the mouse is over the Button in Figure 1.22:
56
In this code, there are four ellipse added to the Window. The animation is applied to all of them. The EventTrigger is added on the click of the Button. When you click the Button, the ellipse starts increasing. The speed of increasing the width of the ellipse is different. The first ellipse increases with the speed specified in the Duration property. In the second ellipse along with the Duration property, AccelerationRatio is also specified, which specifies the increasing speed of the ellipse. In the third ellipse, the Duration and the DecelerationRatio property are specified. In the third ellipse, along with the Duration property, the AccelerationRatio and the DecelerationRatio properties are also specified. When you run the application, by pressing F5, the four ellipses along with the Button, on the Window is visible to you. When you click the StartAnimation button, the ellipse starts growing according to the speed attached to the ellipse. You can see the output after clicking the Button in Figure 1.23:
57
Chapter 1
In this code, two rectangles and a button is added to the Window. The animation is attached on the click event of the Button. When you click the Button, the rectangle starts increasing in Width. The first rectangle stops after increasing as the AutoReverse property is set to False. The second rectangle first increases and then moves back to its original size as the AutoReverse property is set to True. You can see the output after the animation ends in Figure 1.24:
58
the RepeatBehavior property to Forever to repeat the animation indefinitely. Lets create an application to control the behavior of the animation. For this, create a WPF application named ControllingAnimation (available on the CD-ROM) and add the following code given in Listing 1.26 to Window1.xaml: Listing 1.26: Using the RepeatBehavior property
<Window x:Class="ControllingAnimation.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <StackPanel> <Rectangle Height="32" Name="rectangle1" Stroke="Black" Width="90" Fill="Pink"/> <Rectangle Height="32" Name="rectangle2" Stroke="Black" Width="90" Fill="Pink"/> <Rectangle Height="32" Name="rectangle3" Stroke="Black" Width="90" Fill="Pink"/> <Rectangle Height="32" Name="rectangle4" Stroke="Black" Width="90" Fill="Pink"/> <Button Height="23" Name="button1" Width="155">Start</Button> <StackPanel.Triggers> <EventTrigger SourceName="button1" RoutedEvent="Button.Click"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="rectangle1" Storyboard.TargetProperty="Width" From="90" To="200" RepeatBehavior="Forever" Duration="0:0:2"/> <DoubleAnimation Storyboard.TargetName="rectangle2" Storyboard.TargetProperty="Width" From="90" To="200" RepeatBehavior="0:0:2" Duration="0:0:2"/> <DoubleAnimation Storyboard.TargetName="rectangle3" Storyboard.TargetProperty="Width" From="90" To="200" RepeatBehavior="5x" Duration="0:0:2"/> <DoubleAnimation Storyboard.TargetName="rectangle4" Storyboard.TargetProperty="Width" From="90" To="200" Duration="0:0:2"/> </Storyboard> </BeginStoryboard> </EventTrigger> </StackPanel.Triggers> </StackPanel> </Window>
In the code, there are four rectangles and a button added to the Window. The RepeatBehaviour property is attached to all the four rectangles. When you run the code by pressing F5, and click the Start Button, the animation starts and the rectangle starts increasing. You will notice that the first rectangle goes on increasing indefinitely, as the RepeatBehavior property attached with rectangle1 is set to Forever. The second rectangle stops increasing after 2 seconds, as the RepeatBehavior property attached with rectangle2 is set to 0:0:2. The third rectangle stops increasing after five instances, as the RepeatBehavior property attached with rectangle3 is set to 5x. The fourth rectangle increases only once and then stops, as there is no RepeatBehavior property attached with rectangle4. You can see the output after the animation starts in Figure 1.25:
59
Chapter 1
In this code, there is an ellipse, rectangle, and a button. The animation is attached on the click of the Button. When you run the application by pressing F5, and click the Start button, the ellipse and the rectangle starts increasing. After the animation ends, the ellipse stays at the end, while the rectangle comes back to its original state. This is because, the FillBehavior property attached with the ellipse is set to Stop and the rectangle is set to HoldEnd. You can see the output after the animation ends in Figure 1.26:
60
In this code, a Button is added to the application. There are multiple animations applied to the Button. When you run the code by pressing F5, and click the Button, the Button starts changing color. After some time, the Button starts rotating. This type of animation is applied using the ParllelTimeline class. The Button starts changing color after clicking as there is no specified BeginTime property with the color changing event. The Button starts rotating as there is the specified BeginTime property and so the Button starts rotating after the specified time. You can see the output after clicking the Click me button in Figure 1.27:
61
Chapter 1
In XAML
The common practice of controlling a Storyboard is through the XAML code. To start a Storyboard in XAML, you use the BeginStoryboard property and an Event Trigger. The BeginStoryboard property starts the Storyboard. An Event Trigger helps you to implement the animation started by the BeginStoryboard property. Lets create an application to control the Storyboard through the XAML code. For this, create a WPF application named Storyboard_XAML (available on the CD-ROM) and add the following code given in Listing 1.29 to Window1.xaml: Listing 1.29: XAML code
<Window x:Class="Storyboard_XAML.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="500"> <Grid> <Ellipse Height="57" Margin="10,26,0,0" Name="Circle" Stroke="Black" VerticalAlignment="Top" HorizontalAlignment="Left" Width="70" Fill="Aqua"/> <Button HorizontalAlignment="Left" Margin="10,0,0,34" Name="Start" Width="75" Height="23" VerticalAlignment="Bottom">Start</Button> <Button Height="23" Margin="140,0,0,34" Name="Stop" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="75" >Stop</Button> <Button Margin="0,0,332,34" Name="Pause" HorizontalAlignment="Right" Width="75" Height="23" VerticalAlignment="Bottom">Pause</Button> <Button Height="23" Margin="210,0,193,34" Name="Resume" VerticalAlignment="Bottom">Resume</Button> <Button Height="23" HorizontalAlignment="Left" Margin="355,0,0,34" Name="SkipToFill" VerticalAlignment="Bottom" Width="75">SkipToFill</Button> <Button Height="23" HorizontalAlignment="Left" Margin="282,0,0,34" Name="Seek" VerticalAlignment="Bottom" Width="75">Seek</Button> <Grid.Triggers> <EventTrigger RoutedEvent="Button.Click" SourceName="Start"> <BeginStoryboard Name="BeginAnimation"> <Storyboard> <DoubleAnimation Storyboard.TargetName="Circle" Storyboard.TargetProperty="Width" Duration="0:0:3" From="70" To="400"/> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger RoutedEvent="Button.Click" SourceName="Stop"> <StopStoryboard BeginStoryboardName="BeginAnimation"/>
62
In this code, there is an ellipse and six Buttons added to the application. Each Button performs a different function with respect to the Storyboard. When you run the application, by pressing F5, you will notice the behavior of each Button. The Start Button starts the animation and the Storyboard. The Pause Button pauses the Storyboard at wherever point it is specified. The Stop Button stops the Storyboard and brings the ellipse to the start point. The Resume Storyboard resumes the Storyboard from the point it had been paused. The Seek button starts increasing the width of the ellipse from the point specified in the Origin property. The SkipToFill button fills the area of the Storyboard by jumping to the last point. You can see the output in the Figure 1.28:
In Code
When you are controlling the Storyboard through code, you must create a NameScope class for a FrameworkElement class to register the names of the objects to animate with the FrameworkElement class. To start an animation in code, you should use the BeginStoryboard action with an EventTrigger. You can also use an event handler and the Begin method of the Storyboard. You can create the same effect as XAML through the code as well. Lets create an animation in which you can control the Storyboard though code. For this, create a WPF application named Storyboard_Code (available on the CD-ROM) and add the following code given in Listing 1.30 to Window1.xaml: Listing 1.30: Storyboard in Code
<Window x:Class="Storyboard_Code.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Grid> <Button Width="100" Name="button1" Click="button1_Click" HorizontalAlignment="Left" Margin="0,27,0,0" Height="29" VerticalAlignment="Top">Click to grow</Button> </Grid> </Window>
63
Chapter 1
The code in Listing 1.30 is the XAML code, which is used to add a Button named button1 to the application. This Button will be animated in the code-behind file. Add the code given in Listing 1.31 to Window1.xaml.cs: Listing 1.31: Animating Button
using using using using using using using using using using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Windows; System.Windows.Controls; System.Windows.Data; System.Windows.Documents; System.Windows.Input; System.Windows.Media; System.Windows.Media.Imaging; System.Windows.Navigation; System.Windows.Shapes; System.Windows.Media.Animation;
namespace Storyboard_Code { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); NameScope.SetNameScope(this, new NameScope()); this.RegisterName(button1.Name, button1); } private void button1_Click(object sender, RoutedEventArgs e) { DoubleAnimation myAnimation = new DoubleAnimation(); myAnimation.From = 100; myAnimation.To = 300; myAnimation.AutoReverse = true; myAnimation.RepeatBehavior = RepeatBehavior.Forever; myAnimation.Duration = new Duration(TimeSpan.FromSeconds(2)); Storyboard myStoryboard = new Storyboard(); myStoryboard.Children.Add(myAnimation); Storyboard.SetTargetName(myAnimation, button1.Name); Storyboard.SetTargetProperty(myAnimation, new PropertyPath(Button.WidthProperty)); myStoryboard.Begin(this); } } }
The preceding code adds a Storyboard to the Button. The Button is animated to grow as you click on it. When you run the code by pressing F5, a Button is added to the Window. As you click on the Button, it starts increasing. The output is shown in Figure 1.29:
64
65
Chapter 1
<DoubleAnimation Storyboard.TargetName="myBorder" Storyboard.TargetProperty="RenderTransform.ScaleX" From="0" To="1" Duration="0:0:3" AutoReverse="False" /> <DoubleAnimation Storyboard.TargetName="myBorder" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:3" AutoReverse="True" /> </ParallelTimeline> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Button.Triggers> </Button> <Border Width="300" Height="200" Name="myBorder" BorderBrush="Black" BorderThickness="5" Opacity="0.5" Style="{StaticResource WindowStyle}"> <Border.RenderTransform> <ScaleTransform ScaleX="0" ScaleY="1" CenterX="200" /> </Border.RenderTransform> <TextBlock Width="300" Height="300" TextWrapping="Wrap" FontSize="60" TextAlignment="Center"> <TextBlock.Foreground> <RadialGradientBrush GradientOrigin="0,0" Center="0.5,0.5" RadiusX="1" RadiusY="1"> <GradientStop Color="LightPink" Offset="0.25" /> <GradientStop Color="DeepPink" Offset="0.5" /> <GradientStop Color="Pink" Offset="1" /> </RadialGradientBrush> </TextBlock.Foreground> Hello WPF </TextBlock> </Border> </StackPanel> </StackPanel> </Window>
In this code, a Button is added to the Window. When you run the code, by pressing F5, and click the Click to Show Text button, a TextBlock appears on the Window with a scrolling effect. This effect is possible with the help of the transfomming effect of DoubleAnimation. After clicking the Button, the output of the code is shown in Figure 1.30:
66
as local animation. You can use the BeginAnimation method to apply local animation. The local animation cannot be created in the XAML code. You can create local animations in the code-behind file. You should add the System.Windows.Media.Animation namespace in your code file for creating local animation. Lets create animations which are locally created. For this, create a WPF application named LocalAnimation (available on the CD-ROM) and add the following code given in Listing 1.33 to Window1.xaml: Listing 1.33: Creating Local Animation
<Window x:Class="LocalAnimation.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Grid> <Button Height="23" HorizontalAlignment="Left" Margin="25,31,0,0" Name="Button1" VerticalAlignment="Top" Width="91" Click="button1_Click">One Rotation</Button> <Rectangle Margin="131,0,0,50" Name="rectangle1" Stroke="Black" Fill="Aqua" Height="66" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="7" /> <Button Height="23" HorizontalAlignment="Right" Margin="0,31,23,0" Name="button2" VerticalAlignment="Top" Width="75" Click="button2_Click">Forever</Button> <Ellipse Margin="66,82,86,50" Name="ellipse1" Stroke="Black" /> </Grid> </Window>
This is the XAML code which is used to add two buttons, an ellipse, and a rectangle to create a clock type figure. To create a local animation, you need to add the code given in Listing 1.34 to Window1.xaml.cs: Listing 1.34: Local Animation
using using using using using using using using using using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Windows; System.Windows.Controls; System.Windows.Data; System.Windows.Documents; System.Windows.Input; System.Windows.Media; System.Windows.Media.Imaging; System.Windows.Navigation; System.Windows.Shapes; System.Windows.Media.Animation;
namespace LocalAnimation { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void button1_Click(object sender, RoutedEventArgs e) { DoubleAnimation rect = new DoubleAnimation(); rect.From = 0; rect.To = 360; rect.Duration = new Duration(TimeSpan.FromSeconds(7)); RotateTransform rotate = new RotateTransform(); rectangle1.RenderTransform = rotate; rotate.BeginAnimation(RotateTransform.AngleProperty, rect); } private void button2_Click(object sender, RoutedEventArgs e)
67
Chapter 1
{ DoubleAnimation rect = new DoubleAnimation(); rect.From = 0; rect.To = 360; rect.Duration = new Duration(TimeSpan.FromSeconds(7)); rect.RepeatBehavior = RepeatBehavior.Forever; RotateTransform rotate = new RotateTransform(); rectangle1.RenderTransform = rotate; rotate.BeginAnimation(RotateTransform.AngleProperty, rect); } } }
The preceding code adds the animation effect on the click event of the Button. When you click button1, the rectangle which appears as the hand of the clock, rotates and completes one rotation around the ellipse. There is only one rotation as there is no RepeatBehavior property attached to the button1. When you click button2, the rectangle rotates around the ellipse. The rotation keeps on repeating itself, as the RepeatBehavior property attached to button2 is set to Forever. The output of the code is shown in Figure 1.31:
Animating Rectangles
Rectangle is a type of object. The LinearDoubleKeyFrame class is used to animate rectangles. The LinearDoubleKeyFrame class animates the Double value of the previous key frame to its own Value using linear interpolation. A KeyFrame has a target Value and a KeyTime. The KeyTime specifies the time at which the KeyFrame value should be reached. The KeyFrame starts when the previous KeyFrame ends. Lets create an animation of rectangle using the LinearKeyFrame class. For this, create a WPF application named AnimatingRectangle (available on the CD) and add the following code given in Listing 1.35 to Window1.xaml: Listing 1.35: Using LinearDoubleKeyFrame Class
<Window x:Class="AnimatingRectangle.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="400" Width="400"> <Grid> <Rectangle Margin="108,0,130,0" Name="rectangle1" Stroke="Black" Height="40" Width="40" VerticalAlignment="Top" Fill="Red"> <Rectangle.RenderTransform>
68
In this code, a rectangle is added to the Window. When you run the code by pressing F5, you get a red color rectangle on the Window. When you click the rectangle, the rectangle starts moving. The speed of the movement of the rectangle is determined by the KeyTime property. The Value property specifies the position of the rectangle on the Window. The output of the code is shown in Figure 1.32:
Animating Strings
You can animate the string, which means the text, by using KeyFrame. The string is animated using the DiscreteStringKeyFrame class. This class animates the string value of the previous key frame to its own Value using discrete interpolation. Lets create an animation of string using the DiscreteStringKeyFrame class. For this, create a WPF application named AnimatingStrings (available on the CD-ROM) and add the following code given in Listing 1.36 to Window1.xaml:
69
Chapter 1
In this code, a Button with some text is added on the Window. When you run the code by pressing F5, and click the Button, the text disappears from the Button and a new text appears one by one. The text which appears one by one is specified by using the Value property. The difference between the span of time of the text appearing on the Button is specified using the KeyTime property. After clicking the Button, you can see the output in Figure 1.33:
70
frame in the animation. You can specify the KeyTime as a TimeSpan property, as a percentage, or Uniform property or Paced property. Lets create an animation to control the timing of the KeyFrame animation. For this, create a WPF application named ControllingTiming (available on the CD-ROM) and add the following code given in Listing 1.37 to Window1.xaml: Listing 1.37: Using the KeyTime Property
<Window x:Class="ControllingTiming.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="400" Width="400"> <Grid> <Rectangle Margin="17,14,0,0" Stroke="Black" Height="116" VerticalAlignment="Top" Fill="Orange" HorizontalAlignment="Left" Width="125"> <Rectangle.RenderTransform> <TranslateTransform x:Name="RectangleTranform1" X="0" Y="0"/> </Rectangle.RenderTransform> <Rectangle.Triggers> <EventTrigger RoutedEvent="Rectangle.Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="RectangleTranform1" Storyboard.TargetProperty="X" Duration="0:0:10" RepeatBehavior="Forever"> <LinearDoubleKeyFrame Value="350" KeyTime="0:0:10"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Rectangle.Triggers> </Rectangle> <Rectangle Height="54" Margin="17,15,0,0" Stroke="Black" VerticalAlignment="Top" HorizontalAlignment="Left" Width="62" Fill="Red"> <Rectangle.RenderTransform> <TranslateTransform x:Name="RectangleTranform2" X="0" Y="0"/> </Rectangle.RenderTransform> <Rectangle.Triggers> <EventTrigger RoutedEvent="Rectangle.Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="RectangleTranform2" Storyboard.TargetProperty="X" Duration="0:0:10" RepeatBehavior="Forever"> <LinearDoubleKeyFrame Value="350" KeyTime="100%"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Rectangle.Triggers> </Rectangle> <Rectangle Margin="79,68,0,0" Stroke="Black" Height="62" VerticalAlignment="Top" Fill="OrangeRed" HorizontalAlignment="Left" Width="63"> <Rectangle.RenderTransform> <TranslateTransform x:Name="RectangleTranform3" X="0" Y="0"/> </Rectangle.RenderTransform> <Rectangle.Triggers> <EventTrigger RoutedEvent="Rectangle.Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="RectangleTranform3" Storyboard.TargetProperty="X" Duration="0:0:10" RepeatBehavior="Forever"> <LinearDoubleKeyFrame Value="350" KeyTime="Uniform"/> </DoubleAnimationUsingKeyFrames>
71
Chapter 1
</Storyboard> </BeginStoryboard> </EventTrigger> </Rectangle.Triggers> </Rectangle> <Rectangle Height="30" Margin="57,53,0,0" Stroke="Black" VerticalAlignment="Top" HorizontalAlignment="Left" Width="42" Fill="Orange"> <Rectangle.RenderTransform> <TranslateTransform x:Name="RectangleTranform4" X="0" Y="0"/> </Rectangle.RenderTransform> <Rectangle.Triggers> <EventTrigger RoutedEvent="Rectangle.Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="RectangleTranform4" Storyboard.TargetProperty="X" Duration="0:0:10" RepeatBehavior="Forever"> <LinearDoubleKeyFrame Value="350" KeyTime="Paced"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Rectangle.Triggers> </Rectangle> </Grid> </Window>
In this code, rectangle is added to the Window, which starts moving once the Window is loaded. When you run the code by pressing F5, you can see that there are actually four rectangles added to the application, which are moving together in the same pace. This is because of the KeyTime property, which enables the rectangle to move at the same speed. The output of the code is shown in Figure 1.34:
Animating Geometries
There are different types of geometry in WPF, such as Simple Geometry, Path Geometry, and Composite Geometry. You can apply animation to the different types of geometry to create a visually appealing application in WPF. Lets create an application with animating geometries. For this, create a WPF application named AnimatingGeometry (available on the CD-ROM) and add the following code given in Listing 1.38 to Window1.xaml: Listing 1.38: Using Animation for Geometry
<Window x:Class="AnimatingGeometry.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300">
72
In this code, EllipseGeometry is used. An Ellipse is added to the application which is moved using animation. When you run the application by pressing F5, the Ellipse starts moving from the point specified in the From property to the point specified in the To property. The speed of the movement is determined by the Duration property. The output is shown in Figure 1.35:
Animating Cameras
In WPF, you can animate the camera. The camera in WPF is animated using the Point3DAnimation and Vector3DAnimation to animate the Position and LookDirection property of the PerspectiveCamera. The Point3DAnimation class animates the value of the Point3D property using the linear interpolation between the start and the end values. The Vector3DAnimation class animates the value of Vector3D property. Lets create an application of animating the camera of the 3-D model. For this, create a WPF application named AnimatingCamera (available on the CD-ROM) and add the following code given in Listing 1.39 to Window1.xaml:
73
Chapter 1
74
In this code, the 3-D model is added to the application. When you run the application by pressing F5, you can see the 3-D model moving. The animation moves the camera around the object. The object is not changing the position or rotating. It is the moving camera that makes it appear so. As the position of the camera changes using Point3DAnimation, the direction, the camera is pointing to, keeps the object within the view of the camera using the Vector3DAnimation. When you run the code by pressing F5, you get the output as shown in Figure 1.36:
75
Chapter 1
<DirectionalLight Color="White" Direction="-0.612372,0.5,-0.612372" /> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <DirectionalLight Color="White" Direction="0.612372,-0.5,0.612372" /> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D> <GeometryModel3D.Geometry> <MeshGeometry3D TriangleIndices="0,1,2 3,4,5 " Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 " TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 " Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " /> </GeometryModel3D.Geometry> <GeometryModel3D.Material> <MaterialGroup> <DiffuseMaterial> <DiffuseMaterial.Brush> <RadialGradientBrush> <RadialGradientBrush.GradientStops> <GradientStop Color="Yellow" Offset="0.5" /> <GradientStop Color="Red" Offset="1" /> </RadialGradientBrush.GradientStops> </RadialGradientBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> </MaterialGroup> </GeometryModel3D.Material> <GeometryModel3D.Transform> <RotateTransform3D x:Name="myRotateTransform3D" > <RotateTransform3D.Rotation> <AxisAngleRotation3D Axis="0,3,0" Angle="40" /> </RotateTransform3D.Rotation> </RotateTransform3D> </GeometryModel3D.Transform> </GeometryModel3D> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D.Children> <Viewport3D.Triggers> <EventTrigger RoutedEvent="Viewport3D.Loaded"> <BeginStoryboard> <Storyboard> <Rotation3Danimation Storyboard.TargetName="myRotateTransform3D" Storyboard.TargetProperty="Rotation" AutoReverse="True" RepeatBehavior="Forever"> <Rotation3DAnimation.From> <AxisAngleRotation3D Axis="0,3,0" Angle="-60" /> </Rotation3DAnimation.From> <Rotation3DAnimation.To> <AxisAngleRotation3D Axis="1,0,1" Angle="60" /> </Rotation3DAnimation.To> </Rotation3DAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> </Viewport3D.Triggers>
76
In this code, a 3-D object is added to the application. The animation is attached to the 3-D object. When you load the Window, the 3-D object starts moving. The RepeatBehavior property of the 3-D object is set to True. When you run the code by pressing F5, you get the output, as shown in Figure 1.37:
WPF Images
Images in WPF are a core part of most applications. Images in WPF include icon, background, and even part of animation. You can work in a variety of ways with images in WPF. WPF Imaging enables you to display, transform, and format images. WPF imaging is designed to overcome the shortcoming of GDI and provide a new set of API to display and use images within the application. You can access the WPF imaging API in two ways, such as a managed component and an unmanaged component. The managed WPF imaging is available in the System.Windows.Media.Imaging namespace and System.Windows.Media namespace. The managed component utilizes the unmanaged component to provide integration of the images with other WPF features such as animation and graphics. The unmanaged component provides improved performance and security on the local image formats which includes bitmap (BMP), Joint Photographics Experts Group (JPEG), Portable Network Graphics (PNG), Tagged Image File Format (TIFF), Microsoft Windows Media Photo, Graphics Interchange Format (GIF), and icon (.ico). In WPF, the Image class represents the control that displays an image. You can load all the image types supported by WPF with the help of the Image control. The image content is used to determine the final size and location of the control. So, until the image is loaded, the ActualHeight and ActualWidth of the control will
77
Chapter 1
be zero. The Stretch property of the Image control determines how the image is stretched to fill the image element. You can add the Image control to your application by adding the following code:
<Image .../>
The noteworthy properties of the Image control are listed in Table 1.32: Table 1.32: Properties of the Image control
Property
Stretch Source
Description
Gets or sets a value that describes how an Image should be stretched to fill the destination rectangle Gets or sets the ImageSource for the image
You can drag and drop the Image control from the Toolbox and add it to the WPF application. The Image control added to the WPF application is shown in Figure 1.38:
Image control
You can see that, as you add the Image control from the Toolbox, the XAML code is added to the application. Lets now learn about the different image formats used in WPF.
78
pixels at a certain size and resolution. The BitmapSource is an abstract class. The inheritance hierarchy of the BitmapSource class is as follows:
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Freezable System.Windows.Media.Animation.Animatable System.Windows.Media.ImageSource System.Windows.Media.Imaging.BitmapSource
The noteworthy properties of the BitmapSource class are listed in Table 1.33: Table 1.33: Properties of BitmapSource class
Property
CanFreeze DependencyObjectType Dispatcher DpiX DpiY Format HasAnimatedProperties Height IsDownloading IsFrozen IsSealed Metadata Palette PixelHeight PixelWidth Width
Description
Retrieves a value that indicates whether the object can be made unmodifiable Retrieves the DependencyObjectType that wraps the CLR type of this instance Retrieves the Dispatcher the Bitmapsource class DispatcherObject is associated with Retrieves the horizontal dots per inch (dpi) of the image Retrieves the vertical dots per inch (dpi) of the image Retrieves the native PixelFormat of the bitmap data Retrieves a value that indicates whether one or more AnimationClock objects is associated with any of the BitmapSource class dependency properties Retrieves the height of the source bitmap in device-independent units Retrieves a value that indicates whether the BitmapSource content is currently downloading Retrieves a value that indicates whether the object is currently modifiable Retrieves a value that declares whether the BitmapSource class instance is currently read-only Retrieves the metadata that is associated with the bitmap image Retrieves the color palette of the bitmap Retrieves the height of the bitmap in pixels Retrieves the width of the bitmap in pixels Retrieves the width of the bitmap in device-independent units
The noteworthy methods of the BitmapSource class are listed in Table 1.34: Table 1.34: Methods of BitmapSource class
Method
Clone CloneCurrentValue Create CopyPixels
Description
Creates a modifiable clone of the BitmapSource Creates a modifiable clone of the BitmapSource object Creates a new BitmapSource that has the specified properties and options Creates a new BitmapSource class that has the specified properties and options
The BitmapFrame is used to store the actual bitmap data of the image format. The formats such as GIF and TIFF support multiple frames per image, but some image format support a single BitmapFrame.
Image Metadata
Metadata describes the content or characteristic of the file. There is a different metadata associated with each image, but WPF imaging provides a uniform way of storing and retrieving metadata for each image. You can access the metadata of the image through the Metadata property of the BitmapSource object. The Metadata returns a BitmapMetadata object that includes all the metadata information contained by the image. The BitmapMetadata can be a single schema or a collection of schemas. The image metadata schemas supported by WPF imaging are Exchangeable Image File (Exif), tEXt (PNG Textual Data), image file directory (IFD), International Press Telecommunications Council (IPTC), and Extensible Metadata Platform (XMP).
79
Chapter 1
If the BitmapMetadata is exposed by a BitmapFrame that is obtained by using the BitmapDecoder, it is a read-only by default. The mutable operations will throw an exception. If the BitmapMetadata is exposed by a BitmapFrame that wraps another BitmapSource, it is mutable on construction. You can use the GetQuery and SetQuery methods to construct and read metadata queries.
The noteworthy properties of the MediaPlayer class are listed in Table 1.35: Table 1.35: Properties of MediaPlayer class
Property
Balance BufferingProgress CanPause Clock DownloadProgress HasAnimatedProperties HasAudio HasVideo IsBuffering IsFrozen IsMuted NaturalDuration NaturalVideoHeight NaturalVideoWidth Position ScrubbingEnabled
Description
Gets or sets the balance between the left and right speaker volumes Retrieves the percentage of buffering completed for streaming content Retrieves a value indicating whether the media can be paused Gets or sets the MediaClock associated with the MediaTimeline to be played Retrieves the percentage of download progress for content located at a remote server Retrieves a value that indicates whether one or more AnimationClock objects is associated Retrieves a value that indicating whether the media has audio output Retrieves a value that indicates whether the media has video output Retrieves a value that indicates whether the media is buffering Retrieves a value that indicates whether the object is currently modifiable Retrieves a value that indicates whether the media is muted Retrieves the natural duration of the media Retrieves the pixel height of the video Retrieves the pixel width of the video Gets or sets the current position of the media Gets or sets a value that indicates whether scrubbing is enabled
80
Property
Source SpeedRatio Volume
Description
Retrieves the media Uri Gets or sets the ratio of speed that media is played at Gets or sets the medias volume
The noteworthy methods of the MediaPlayer class are listed in Table 1.36: Table 1.36: Methods of MediaPlayer class
Method
Close Play Pause Stop
Description
Closes the media. Begins playback Pauses playback but does not change the position Stops playback and resets the position to the beginning of the file
The MediaElement is the WPF element that wraps all the functionality of the MediaPlayer class. You can declare an instance of the MediaElement in the XAML. You should note that if you are the MediaElement for video, you should place it where the video window should appear. The inheritance hierarchy of the MediaElement class is as follows:
System.Object System.Windows.Threading.DispatcherObject System.Windows.DependencyObject System.Windows.Media.Visual System.Windows.UIElement System.Windows.FrameworkElement System.Windows.Controls.MediaElement
The noteworthy properties of the MediaElement class are listed in Table 1.37: Table 1.37: Properties of MediaElement class
Property
Balance BufferingProgress CanPause Clock DownloadProgress HasAudio HasVideo IsBuffering IsMuted LoadedBehavior NaturalDuration NaturalVideoHeight NaturalVideoWidth Position ScrubbingEnabled Source SpeedRatio
Description
Gets or sets a ratio of volume across speakers Retrieves a value that indicates the percentage of buffering progress made Retrieves a value indicating whether the media can be paused Gets or sets the clock associated with the MediaTimeline that controls media playback Retrieves a percentage value indicating the amount of download completed for content located on a remove server Retrieves a value indicating whether the media has audio Retrieves a value indicating whether the media has video Get a value indicating whether the media is buffering Gets or sets a value indicating whether the audio is muted Gets or sets the load behavior MediaState for the media Retrieves the natural duration of the media Retrieves the height of the video associated with the media Retrieves the width of the video associated with the media Gets or sets the current position of progress through the medias playback time Gets or sets a value that indicates whether the MediaElement will update frames for seek operations while paused Gets or sets a media source on the MediaElement Gets or sets the speed ratio of the media
81
Chapter 1
Property
Stretch UnloadedBehavior Volume
Description
Gets or sets a Stretch value that describes how a MediaElement fills the destination rectangle Gets or sets the unload behavior MediaState for the media Gets or sets the media volume
The noteworthy methods of the MediaElement class are listed in Table 1.38: Table 1.38: Methods of MediaElement class
Method
ArrangeOverride MeasureOverride OnCreateAutomationPeer OnRender
Description
Arranges and sizes a MediaElement control Updates the DesiredSize of the MediaElement Creates and returns an AutomationPeer object for the MediaElement Draws the content of a DrawingContext object during the render pass of a MediaElement control
You can drag and drop the MediaElement control from the Toolbox and add it to the WPF application. The MediaElement control added to the WPF application is shown in Figure 1.39:
MediaElement control
You can see that as you add the MediaElement control from the Toolbox, the XAML code is added to the application.
You should set the LoadedBehavior property of the MediaElement to Manual in order to interactively stop, pause, and play the media.
82
the media object control methods which are Play, Pause, Close, and Stop. You can control the media playback in the clock mode by using the ClockController control methods. The ClockController is obtained from the ClockController property of the MediaClock. You cannot use the media object control methods in the Clock mode. If you attempt to use the method, an InvalidOperationException will be thrown. The MediaPlayer class is used in two different modes: independent mode and clock mode. In the independent mode, the MediaPlayer is like an image and the media which is opened by the Open method drives the playback. In the clock mode, the MediaPlayer can be combined with animation, and so it will have the corresponding Timeline and Clock class attached to it. You should use the VideoDrawing or DrawingContext class to display media loaded using MediaPlayer. The MediaElement can also be used in two different modes: independent or clock mode. In the independent mode, the MediaElement is similar to an image, and the Source URI can be directly specified. In the clock mode, the MediaElement can be used with animation, and so will have the Timeline and Clock class.
You need to change the path of the image specified in the UriSource according to the image location in your system.
In this code, an image is loaded to the application using the Image control. The Stretch property determines how the image is stretched to fill the Image control. When you run the code by pressing F5, you get the output as shown in Figure 1.40:
83
Chapter 1
You have learned about the Image control in detail in Chapter 17, Templates, and Commands.
Working
Transforming Images
In WPF, you can transform images using the properties of the BitmapImage. The different transformations that you can apply to a WPF image are rotating, converting, and cropping the image. You can rotate an image by using the Rotation property of the BitmapImage. You can convert an image to a different pixel format, such as grayscale, by using the FormatConvertedBitmap class. You can crop an image either by using the Clip property or the CroppedBitmap property. If you want to display a portion of an image, you should use the Clip property and if you want to encode and save a cropped image, the CroppedBitmap should be used. Lets create an application and perform the different transformations. For this, create a WPF application named TransformingImages (available on the CD) and add the following code given in Listing 1.42 to Window1.xaml: Listing 1.42: Transformation of Images
<Window x:Class="TransformingImages.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="400" Width="400"> <Grid> <Image Width="150" HorizontalAlignment="Left" VerticalAlignment="Top"> <Image.Source> <TransformedBitmap Source="C:\Users\avantika\Documents\Visual Studio 2008\Projects\TransformingImages\Image.jpg" > <TransformedBitmap.Transform> <RotateTransform Angle="180"/> </TransformedBitmap.Transform> </TransformedBitmap> </Image.Source> </Image> <Image Width="150" HorizontalAlignment="Right" VerticalAlignment="Top"> <Image.Source> <FormatConvertedBitmap Source="C:\Users\avantika\Documents\Visual Studio 2008\Projects\TransformingImages\Image.jpg" DestinationFormat="Gray4" /> </Image.Source> </Image> <Image Width="200" Source="C:\Users\avantika\Documents\Visual Studio 2008\Projects\TransformingImages\Image.jpg" HorizontalAlignment="Center" VerticalAlignment="Center">
84
In this code, a single image is transformed in three different ways. In the first image, the image is rotated using the RotateTransform property. The second image is converted to a different pixel format. The third image is cropped using the EllipseGeometry. When you run the code by pressing F5, you get the output as shown in Figure 1.41:
Stretching Images
You can use the Stretch property of the Image control to control how an image is stretched to fill the container. The values of the Stretch property are None, Fill, Uniform, and UniformToFill. The image is not stretched if the Stretch property is set to None. If the image is larger than the output area, then the image is clipped. The Fill value scales the image to fill the output area. In this case, the aspect ratio of the image may not be preserved. The Uniform value scales the image, so that it completely fits the output area. The aspect ratio of the image in this case is preserved. The UniformToFill value scales the image to completely fill the output area. The aspect ratio of the image is preserved. Lets use the Strecth property on the Image control. For this, create a WPF application named StretchingImages (available on the CD-ROM) and add the following code given in Listing 1.43 to Window1.xaml: Listing 1.43: Using the Stretch Property
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > <DockPanel> <Grid Margin="10" ShowGridLines="True" VerticalAlignment="Center" HorizontalAlignment="Center"> <Grid.ColumnDefinitions> <ColumnDefinition Width="175" /> <ColumnDefinition Width="175" /> <ColumnDefinition Width="175" /> <ColumnDefinition Width="175" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition />
85
Chapter 1
<RowDefinition Height="200"/> </Grid.RowDefinitions> <Border Grid.Column="0" Grid.Row="1" BorderThickness="3" BorderBrush="Black"> <Image Source="C:\Users\avantika\Documents\Visual Studio 2008\Projects\StretchingImages\Image.jpg" Stretch="None" /> </Border> <Border Grid.Column="1" Grid.Row="1" BorderThickness="3" BorderBrush="Black"> <Image Source="C:\Users\avantika\Documents\Visual Studio 2008\Projects\StretchingImages\Image.jpg" Stretch="Uniform" /> </Border> <Border Grid.Column="2" Grid.Row="1" BorderThickness="3" BorderBrush="Black"> <Image Source="C:\Users\avantika\Documents\Visual Studio 2008\Projects\StretchingImages\Image.jpg" Stretch="UniformToFill" /> </Border> <Border Grid.Column="3" Grid.Row="1" BorderThickness="3" BorderBrush="Black"> <Image Source="C:\Users\avantika\Documents\Visual Studio 2008\Projects\StretchingImages\Image.jpg" Stretch="Fill" /> </Border> </Grid> </DockPanel> </Page>
In this code, images are displayed on the Window. The same image is displayed using the four values of the Strecth property. When you run the code by pressing F5, you get the output as shown in Figure 1.42:
86
You need to change the path of the media file specified in this application as well as all the applications in this chapter that are using the media file according to its location in your system.
In this code, two labels, three buttons and two sliders are added to the application along with MediaElement control. The buttons are used for playing, pausing, and stopping the media. The sliders are used to control the volume and change the speed of the music. To control the functioning of the Button control and the Slider control, you need to add the code given in Listing 1.45: Listing 1.45: Adding code for Controlling the Controls
using using using using using using using using using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Windows; System.Windows.Controls; System.Windows.Data; System.Windows.Documents; System.Windows.Input; System.Windows.Media; System.Windows.Media.Imaging; System.Windows.Navigation; System.Windows.Shapes;
namespace MediaElement { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void button1_Click(object sender, RoutedEventArgs e) { mediaElement1.Position = TimeSpan.Zero; mediaElement1.Play(); } private void button2_Click(object sender, RoutedEventArgs e)
87
Chapter 1
{ mediaElement1.Stop(); } private void button3_Click(object sender, RoutedEventArgs e) { mediaElement1.Pause(); mediaElement1.Position = TimeSpan.FromSeconds(slider1.Value); } private void ChangeMediaVolume(object sender, RoutedPropertyChangedEventArgs<double> args) { mediaElement1.Volume = (double)slider1.Value; } private void ChangeMediaSpeedRatio(object sender, RoutedPropertyChangedEventArgs<double> args) { mediaElement1.SpeedRatio = (double)slider2.Value; } } }
In this code, the click event of the Button control and the movement of the Slider control are controlled. When you run the code by pressing F5, you can see the output as shown in Figure 1.43:
If you do not add the buttons for controlling the playback of the media, the media loaded using the MediaElement control plays automatically once the Window is loaded.
88
In this code, a Button is added to the Window. The media is attached to the click event of the Button. The code for the click event of Button is given in Listing 1.47: Listing 1.47: Adding code for the MediaPlayer
using using using using using using using using using using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Windows; System.Windows.Controls; System.Windows.Data; System.Windows.Documents; System.Windows.Input; System.Windows.Media; System.Windows.Media.Imaging; System.Windows.Navigation; System.Windows.Shapes; System.Windows.Media.Animation;
namespace UsingMediaPlayer { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void button1_Click(object sender, RoutedEventArgs e) { MediaTimeline myTime = new MediaTimeline(new Uri(@"C:\Users\avantika\Documents\Visual Studio 2008\Projects\UsingMediaPlayer\Love Comes.wma", UriKind.Relative)); myTime.RepeatBehavior = RepeatBehavior.Forever; MediaClock myClock = myTime.CreateClock(); MediaPlayer myPlayer = new MediaPlayer(); myPlayer.Clock = myClock; VideoDrawing myDrawing = new VideoDrawing(); myDrawing.Rect = new Rect(0, 0, 100, 100); myDrawing.Player = myPlayer; } } }
The code calls the media file when you click the Button. The final output is shown in Figure 1.44:
89
Chapter 1
The media file attached to the code plays when you click the Button.
90
In this code, MediaTimeline control is added to play media file. The Buttons are added to control the playback of the media. The Slider is added to show the progress of media. The playback of media is controlled by using the Storyboard on the click of the Button. The functionality for the progress bar, which is the Slider control, is added through the code file given in Listing 1.49: Listing 1.49: Controlling the Slider Control
using using using using using using using using using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Windows; System.Windows.Controls; System.Windows.Data; System.Windows.Documents; System.Windows.Input; System.Windows.Media; System.Windows.Media.Imaging; System.Windows.Navigation; System.Windows.Shapes;
namespace Storyboard_MediaPlayback { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void Element_MediaOpened(object sender, EventArgs e) { slider1.Maximum = mediaElement1.NaturalDuration.TimeSpan.TotalMilliseconds; } private void MediaTimeChanged(object sender, EventArgs e) { slider1.Value = mediaElement1.Position.TotalMilliseconds; } } }
In this code, the functionality of the progress bar is controlled. When you run the code by pressing F5, the Window with the Button for Play, Pause, Resume, and Stop along with the Slider is displayed. As you click the Play Button, the media starts playing. The Slider progresses as the media is playing. After running the code, you can see the Window as shown in Figure 1.45:
91
Chapter 1
The code in Listing 1.50 will add a Button to the Window1. When you will click the Button, the Window1 will close itself and a new Window with the name Window2 will appear which will be playing the animation and the media file. For the Window1 to close and the new Window to open, you need to add the code given in Listing 1.51 in the code-behind file, which is Window1.xaml.cs: Listing 1.51: Adding code on the Click Event of button1
using using using using using using using using using using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Windows; System.Windows.Controls; System.Windows.Data; System.Windows.Documents; System.Windows.Input; System.Windows.Media; System.Windows.Media.Imaging; System.Windows.Navigation; System.Windows.Shapes; System.Diagnostics;
namespace PlayingMedia_UserEvent { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { // InitializeComponent(); } private void button1_Click(object sender, RoutedEventArgs e) { Window2 myWindow = new Window2(); myWindow.Show(); this.Close(); } } }
You need to load a new Window on the click of the Button and play the media and animation on the second Window. For this, right-click the project name which is PlayingMedia_UserEvent in the Solution Explorer. Select Add New Item, as shown in Figure 1.46:
92
The Add New Item Window opens. Select Window(WPF) and provide a name to it, if you wish. The default name is Window2.xaml and click on Add, as shown in Figure 1.47:
A new Window with the name Window2.xaml is added to your project. Listing 1.52: Adding XAML code for media and animation to Window2
<Window x:Class="PlayingMedia_UserEvent.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window2" Height="300" Width="300"> <Canvas Background="Pink"> <Path Stroke="Purple" StrokeThickness="10"> <Path.Data> <EllipseGeometry x:Name="MyEllipseGeometry" Center="125,125" RadiusX="50" RadiusY="25" /> </Path.Data> </Path> <Path Stroke="Gold" StrokeThickness="10"> <Path.Data>
93
Chapter 1
<EllipseGeometry x:Name="MyEllipseGeometry2" Center="125,125" RadiusX="25" RadiusY="50" /> </Path.Data> </Path> <MediaElement Name="mediaElement1"> <MediaElement.Triggers> <EventTrigger RoutedEvent="MediaElement.Loaded"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard SlipBehavior="Slip"> <MediaTimeline Source="C:\Users\avantika\Documents\Visual Studio 2008\Projects\PlayingMedia_UserEvent\Media.wma" BeginTime="0:0:0"> </MediaTimeline> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="MyEllipseGeometry" Storyboard.TargetProperty="RadiusY" RepeatBehavior="Forever"> <DoubleAnimationUsingKeyFrames.KeyFrames> <LinearDoubleKeyFrame Value="100" KeyTime="0:0:4"/> </DoubleAnimationUsingKeyFrames.KeyFrames> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="MyEllipseGeometry2" Storyboard.TargetProperty="RadiusX" RepeatBehavior="Forever"> <DoubleAnimationUsingKeyFrames.KeyFrames> <LinearDoubleKeyFrame Value="100" KeyTime="0:0:4"/> </DoubleAnimationUsingKeyFrames.KeyFrames> </DoubleAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </MediaElement.Triggers> </MediaElement> </Canvas> </Window>
As you run the code by pressing F5, the Window1 will appear as shown in Figure 1.48:
When you click the Button on Window1, it disappears and Window2 is loaded, which plays the animation along with the media file. The output of Window2 is shown in Figure 1.49:
94
In this code, the MediaElement is added to the Window. The MediaElement control is added to the application which is transformed using RotateTransform. A Button is added to the application and the code is added on the click event of the Button control for the media file to play. The code for the click event of the Button control is given in Listing 1.54: Listing 1.54: Adding code for the click event of Button
using using using using using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.Windows; System.Windows.Controls; System.Windows.Data; System.Windows.Documents; System.Windows.Input;
95
Chapter 1
using using using using System.Windows.Media; System.Windows.Media.Imaging; System.Windows.Navigation; System.Windows.Shapes;
namespace TransformingVideo { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void button1_Click(object sender, RoutedEventArgs e) { myMedia.Position = TimeSpan.Zero; myMedia.Play(); } } }
In this code, the click event of the Button control is added. When you run the code in Listing 1.53 and Listing 1.54 by pressing F5, you get the output Window, as shown in Figure 1.50, with the Button added to it. When you click the Play button, the media file is loaded to the Window:
Summary
In this chapter, you have learned about drawing graphics in Windows Form applications with the help of different classes. You have also learned about using the graphics, animation, and multimedia features in WPF 3.5. In addition, you have learned about creating different shapes and geometries and adding colors to them with the help of brushes. The chapter also describes use of multimedia in WPF 3.5. In the next chapter, you learn about data binding in Windows Form and WPF applications
Quick Revise
Q1. Ans. __________ is the successor to GDI which is responsible for the integration of graphics in Window Form. GDI+.
96
Q6. Ans.
Q7. Ans.
Q8. Ans.
Q9. Ans.
The __________ class enables you to combine a collection of drawings that can be operated as a single drawing. DrawingGroup. You can use a Storyboard to group multiple animations. (True/False) True. The BitmapSource classe is used in WPF to present audio, video, and video with audio content. (True/False) False. Mention the important classes in WPF that allow you to work with the 2-D graphics. The WPF classes that pertain to 2-D graphics are: The System.Windows.Shapes.Shape class: Provides the functionality to work with simple 2-D shapes such as ellipse and rectangle The System.Windows.Media.Geometry class: Provides the functionality to work with geometric shapes and curves The System.Windows.Media.Drawing class: Provides the functionality to work with 2-D drawings What are the brushes that are available in WPF? The brushes available in WPF are objects of the classes that inherit the System.Windows.Media.Brush class. The brushes that are available in WPF 3.5 are: SolidColorBrushPaints a given area with a solid color LinearGradientBrushPaints a given area with linear gradient RadialGradientBrushPaints a given area with radial gradient DrawingBrushPaints a given area with a drawing ImageBrushPaints a given area with an image VisualBrushPaints a given area with a Visual object How many types of projection cameras are available for 3-D graphics in WPF? WPF supports mainly two types of projection cameras for 3-D objects: Orthographic cameraRenders the 3-D scene such that the exact scale of the object is preserved Perspective cameraRenders the 3-D scene such that the objects that are far appear smaller, while the objects that are near appear larger What are the different kinds of animation supported in WPF? WPF has a rich support for animations, which can be used to change property values, reposition elements, change colors, and so on. The functionality to create and manipulate animations is provided by the System.Windows.Media.Animation namespace. Animation in WPF can be of three types: Basic animationRefers to the animation in WPF that is created by changing the property value from a starting value to a destination value. Alternatively, an offset value can also be provided to indicate the amount of change during the animation. The stating value is specified by the From property, the destination value is specified by the To property, and the offset value is specified by the By property. This is why basic animation is also known as From/To/By animation. Keyframe animationRefers to the animation that is created by using keyframes, which are the destination values for a property. There can be several keyframes in a single keyframe animation. Path animationRefers to the animation that is created by changing the property value with respect to a given path described by a PathGeometry object. It is ideal for situations when the movement of an object or element has to be along a path. The lines and curves in the given path determine the property value. What are the two modes of media playback? The MediaPlayer and MediaElement controls have two modes in which media can be played back. These two modes depend on the Clock property of the controls. The two playback modes are:
97
Chapter 1
Q10. Ans.
Clock modeRefers to the mode when the Clock property is set to any value other than the null value. The methods of the ClockController object are used to control the playback of the media. Independent modeRefers to the mode when the Clock property is set to the null value. The Play, Pause, Close, and Stop methods can be used to control the playback of the media in the independent mode. What are the image formats supported in WPF? The file formats of images that are supported in WPF are: Bitmap (.bmp) Joint Photographic Experts Group (.jpg and .jpeg) Portable Network Graphics (.png) Tagged Image File Format (.tiff) Graphics Interchange Format (.gif) Icon (.ico) Windows Media Photo
98