charles petzold xaml. agenda layout and positioning shapes, brushes, and brush resources text,...
TRANSCRIPT
Agenda
• Layout and positioning• Shapes, brushes, and brush resources• Text, fonts, and font resources• Images and writeable bitmaps• UI element properties• Creating XAML objects programmatically• Transforms and projections• Animations and animation easing• GPU caching
• Controls for positioning UI elements• More in the Silverlight for Windows Phone
Toolkit
Layout Controls
Control Description
Canvas Positions elements using pixel coordinates
Grid Arranges objects in rows and columns
StackPanel Arranges objects in a row or a column
• Allows absolute positioning of elements
Canvas
<Canvas> <Rectangle Canvas.Left="50" Canvas.Top="50" Width="100" Height="100" Fill="Red" /> <Canvas Canvas.Left="200" Canvas.Top="100" Width="200" Height="200" Background="Yellow"> <Rectangle Canvas.Left="50" Canvas.Top="50" Width="100" Height="100" Fill="Blue" /> </Canvas></Canvas>
• Stacks elements horizontally or vertically
StackPanel
<StackPanel Orientation="Horizontal"> <Rectangle Width="100" Height="100" Fill="Red" /> <Rectangle Width="100" Height="100" Fill="Green" /> <Rectangle Width="100" Height="100" Fill="Blue" /></StackPanel>
• Arranges elements in rows and columns
Grid
<Grid ShowGridLines="true"> <Grid.RowDefinitions> <RowDefinition Height="150" /> <RowDefinition Height="150" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="150" /> <ColumnDefinition Width="150" /> </Grid.ColumnDefinitions> <Rectangle Width="100" Height="100" Fill="Red" Grid.Row="0" Grid.Column="0" /> <Rectangle Width="100" Height="100" Fill="Green" Grid.Row="0" Grid.Column="1" /> <Rectangle Width="100" Height="100" Fill="Blue" Grid.Row="1" Grid.Column="0" /> <Rectangle Width="100" Height="100" Fill="Yellow" Grid.Row="1" Grid.Column="1" /></Grid>
• Absolute sizing: Width="200"• Automatic sizing: Width="Auto"
– Column width == Width of widest object in column
• Proportional sizing:
Sizing Rows and Columns
<Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="2*" /> <ColumnDefinition Width="*" /></Grid.ColumnDefinitions>
25% of total width50% of total width25% of total width
• FrameworkElement's HorizontalAlignment and VerticalAlignment properties control alignment
Alignment
<Rectangle Width="100" Height="100" Fill="Red" HorizontalAlignment="Left" VerticalAlignment="Top" /><Rectangle Width="100" Height="100" Fill="Green" Margin="10" HorizontalAlignment="Right" VerticalAlignment="Bottom" />
• FrameworkElement's Margin property creates padding around elements
Margins
<StackPanel Orientation="Horizontal"> <Rectangle Width="100" Height="100" Fill="Red" Margin="10" /> <Rectangle Width="100" Height="100" Fill="Green" Margin="10" /> <Rectangle Width="100" Height="100" Fill="Blue" Margin="10" /></StackPanel>
Paths
<Path Fill="Yellow" Stroke="Black" StrokeThickness="4" StrokeEndLineCap="Round" StrokeLineJoin="Round" Data="M 200,200 C 200,300 330,250 580,140 C 330,300 130,450 200,200" />
• Objects used to color XAML UI elements• Apply using property-element syntax
Brushes
Brush Description
SolidColorBrush Renders a solid color
LinearGradientBrush Renders a linear gradient
RadialGradientBrush Renders a radial gradient
ImageBrush Renders an image
• Allows properties to be assigned nontrivial values
Property-Element Syntax
<Rectangle Height="200" Width="300" Stroke="Black" StrokeThickness="10"> <Rectangle.Stroke> <SolidColorBrush Color="Black" /> </Rectangle.Stroke> <Rectangle.Fill> <SolidColorBrush Color="Yellow" /> </Rectangle.Fill></Rectangle>
LinearGradientBrush
<Rectangle Height="200" Width="300" Stroke="Black" StrokeThickness="10"> <Rectangle.Fill> <LinearGradientBrush> <GradientStop Color="Yellow" Offset="0.0" /> <GradientStop Color="Red" Offset="0.25" /> <GradientStop Color="Blue" Offset="0.75" /> <GradientStop Color="LimeGreen" Offset="1.0" /> </LinearGradientBrush> </Rectangle.Fill></Rectangle>
RadialGradientBrush
<Rectangle Height="200" Width="300" Stroke="Black" StrokeThickness="10"> <Rectangle.Fill> <RadialGradientBrush GradientOrigin="0.5,0.5" Center="0.5,0.5" RadiusX="0.5" RadiusY="0.5"> <GradientStop Color="Yellow" Offset="0" /> <GradientStop Color="Red" Offset="0.25" /> <GradientStop Color="Blue" Offset="0.75" /> <GradientStop Color="LimeGreen" Offset="1" /> </RadialGradientBrush> </Rectangle.Fill></Rectangle>
• Approximately 25 built-in brush resources– PhoneAccentBrush and PhoneSubtleBrush– PhoneBackgroundBrush and
PhoneForegroundBrush– PhoneChromeBrush and PhoneDisabledBrush– PhoneBorderBrush and many others
• Colors change with theme and accent colors• Complete list at
http://msdn.microsoft.com/en-us/library/ff769552(v=vs.92).aspx
• Also in ThemeResources.xaml
Stock Brush Resources
Stock Brush Resources in Action
Dark themeBlue accent
Light themeBlue accent
Dark themeOrange accent
Using Stock Brush Resources
<Rectangle Width="300" Height="80" Stroke="{StaticResource PhoneBorderBrush}" Fill="{StaticResource PhoneAccentBrush}" />
{StaticResource} markup extension loads the specified resource
TextBlock
<TextBlock FontSize="120" FontFamily="Georgia" FontStyle="Italic" FontWeight="Bold"> Silverlight <TextBlock.Foreground> <LinearGradientBrush> <GradientStop Color="Yellow" Offset="0.0" /> <GradientStop Color="Red" Offset="0.25" /> <GradientStop Color="Blue" Offset="0.75" /> <GradientStop Color="LimeGreen" Offset="1.0" /> </LinearGradientBrush> </TextBlock.Foreground></TextBlock>
• Default is Segoe WP• Approx. 15 fonts provided in ROM on
phones– Arial, Courier New, Georgia, Times New Roman,
Segoe WP, Tahoma, Trebuchet MS, Verdana, and more
– Complete list at http://msdn.microsoft.com/en-us/library/ff806365%28v=VS.95%29.aspx
• Custom fonts supported, too
Fonts
• Build TTFs into application assembly as resources– Also works with ZIP files containing TTFs
• Reference individual fonts using syntax FontFamily="filename#fontname"
Custom Fonts
<TextBlock FontFamily="MyHandwriting.ttf#ChickenScratch"> Silverlight</TextBlock>
• Built-in FontFamily resources– PhoneFontFamilyNormal, PhoneFontFamilyLight,
PhoneFontFamilySemiLight, PhoneFontFamilySemiBold
• Built-in FontSize resources– PhoneFontSizeSmall, Normal, Medium,
MediumLarge, Large, ExtraLarge, ExtraExtraLarge, Huge
• Built-in Style resources– PhoneTextNormalStyle, PhoneTextAccentStyle,
PhoneTextContrastStyle, and many others– Combine FontFamily, FontSize, and Foreground
Stock Font Resources
Stock Font Resources in Action
PhoneTextNormalStyle
PhoneTextTitle1Style
PhoneTextExtraLargeStyle
PhoneTextSubtleStyle
PhoneTextAccentStyle
Using Stock Font Resources
<TextBlock ... Style="{StaticResource PhoneTextExtraLargeStyle}" /><TextBlock ... Style="{StaticResource PhoneTextAccentStyle}" />
{StaticResource} markup extension loads the specified resource
Images
<Image Source="Bandit.jpg" /><Image Source="http://www.wintellect.com/images/Bandit.jpg" /><Image Source="Images/Bandit.jpg" Stretch="None" /><Image Source="Images/Bandit.jpg" Width="400" />
• Set build action to Content, not Resource, for images and other media– Both work– Resource is the
default– Content is faster
Images and Build Actions
• Silverlight's pixel-addressable bitmap API– Pixels exposed through Pixels property– One-dimensional array (row-first order)
• Create bitmaps from scratch• Create bitmaps from Image objects• Render all or part of the XAML tree to a
bitmap
WriteableBitmap
Generating an Image
WriteableBitmap bitmap = new WriteableBitmap(width, height);
for (int x = 0; x < width; x++){ for (int y = 0; y < height; y++) { bitmap.Pixels[(y * width) + x] = unchecked((int)0xFF000000); // ARGB (black) }}
bitmap.Invalidate();
// Copy WriteableBitmap bits to a XAML ImageMyImage.Source = bitmap;
Modifying a XAML Image
WriteableBitmap bitmap = new WriteableBitmap((BitmapImage)MyImage.Source);
for (int x = 0; x < bitmap.PixelWidth; x++){ for (int y = 0; y < bitmap.PixelHeight; y++) { // TODO: Modify pixel at bitmap.Pixels[[(y * width) + x] }}
bitmap.Invalidate();
// Copy WriteableBitmap bits to back to the XAML ImageMyImage.Source = bitmap;
Rendering XAML to a Bitmap
// Create a WriteableBitmapWriteableBitmap bitmap = new WriteableBitmap(width, height);
// Render Canvas named "TargetCanvas" to the bitmapbitmap.Render(TargetCanvas, null);bitmap.Invalidate();
// Copy WriteableBitmap bits to a XAML ImageMyImage.Source = bitmap;
Properties of UI Elements
Property Description
Clip Clips an element using a specified geometry
Cursor Specifies the appearance of the mouse cursor over an element
IsHitTestVisible Determines whether an element fires touch events
Opacity Specifies an element's opacity (0.0 – 1.0)
OpacityMask Varies opacity using a gradient brush
Style Applies a style to an element
Visibility Controls an element's visibility
Canvas.ZIndex Specifies an element's Z-index
• Controls visibility of XAML objects– Visibility.Visible (default) – Visible– Visibility.Collapsed – Not visible
• Use Opacity, not Visibility, to hide objects temporarily (opposite desktop guidance)
Visibility
// XAML<Ellipse x:Name="Ball" Width="300" Height="200" Fill="Red" />
// C#Ball.Visibility = Visibility.Collapsed; // Make it disappear
Opacity
<Ellipse Canvas.Left="50" Canvas.Top="50" Stroke="Black" Height="200" Width="300" StrokeThickness="10" Fill="Red" Opacity="0.5" /><Ellipse Canvas.Left="200" Canvas.Top="50" Stroke="Black" Height="200" Width="300" StrokeThickness="10" Fill="#80FFFF00" />
OpacityMask
<TextBlock Text="Silverlight" Foreground="White" ... /><TextBlock Text="Silverlight" Foreground="White" ...> ... <TextBlock.OpacityMask> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop Offset="0.5" Color="#00000000" /> <GradientStop Offset="1" Color="#80000000" /> </LinearGradientBrush> </TextBlock.OpacityMask></TextBlock>
Canvas.ZIndex
<Ellipse Canvas.Left="50" Canvas.Top="50" Stroke="Black" Height="200" Width="300" StrokeThickness="10" Fill="Red" Canvas.ZIndex="1" /><Ellipse Canvas.Left="200" Canvas.Top="50" Stroke="Black" Height="200" Width="300" StrokeThickness="10" Fill="Yellow" Canvas.ZIndex="0" />
• Direct instantiation– Ellipse e = new Ellipse();– One object at a time
• XamlReader.Load– Creates object(s) from XAML strings– One object or tree of objects
• Add object(s) to XAML DOM separately
Creating XAML Objects at Run-Time
Direct Instantiation
Ellipse ellipse = new Ellipse();ellipse.SetValue(Canvas.LeftProperty, 50.0);ellipse.SetValue(Canvas.TopProperty, 50.0);ellipse.Width = 100.0;ellipse.Height = 100.0;ellipse.Fill = new SolidColorBrush(Colors.Red); Placeholder.Children.Add(ellipse);
XamlReader.Load
string xaml = "<Ellipse " + "xmlns=\"http://schemas.microsoft.com/client/2007\" " + "Canvas.Left=\"50\" Canvas.Top=\"50\" " + "Width=\"100\" Height="\100\" Fill=\"Red\" />";FrameworkElement ellipse = (FrameworkElement) XamlReader.Load(xaml);Placeholder.Children.Add(ellipse);
• Enable objects or groups of objects to be translated, rotated, scaled, and skewed
• Applied by assigning Transform object(s) to visual element's RenderTransform property– RenderTransform applies transform to objects
after layout is performed (not before)– Silverlight doesn't support LayoutTransform
• Applies transform to objects before layout• The basis for many advanced visual effects
Transforms
RotateTransform
<Rectangle Fill="Yellow" Stroke="Black" Height="200" Width="300" StrokeThickness="10"> <Rectangle.RenderTransform> <RotateTransform Angle="30" /> </Rectangle.RenderTransform></Rectangle>
X
Y
(0,0)
30o
<Rectangle Fill="Yellow" Stroke="Black" Height="200" Width="300" StrokeThickness="10"> <Rectangle.RenderTransform> <RotateTransform Angle="30" CenterX="150" CenterY="100" /> </Rectangle.RenderTransform></Rectangle>
Controlling Center of Rotation
X
Y
30o
<Rectangle Fill="Yellow" Stroke="Black" Height="200" Width="300" StrokeThickness="10" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="30" /> </Rectangle.RenderTransform></Rectangle>
• XAML property that controls transform origin using normalized coordinates– 0,0 = Upper left corner– 1,1 = Lower right corner
RenderTransformOrigin
• Use <TransformGroup> element to apply multiple transforms to a XAML element
• Transforms applied in top-to-bottom order
TransformGroup
<Rectangle ...> <Rectangle.RenderTransform> <TransformGroup> <RotateTransform Angle="135" /> <ScaleTransform ScaleX="1.5" ScaleY="1.2" /> </TransformGroup> </Rectangle.RenderTransform></Rectangle>
• One transform that does it all• Applies transforms in following order:
– Scale, Skew, Rotate, Translate
CompositeTransform
<Rectangle ...> <Rectangle.RenderTransform> <CompositeTransform Rotation="135" ScaleX="1.5" ScaleY="1.2" TranslateX="100" SkewX="30" /> </Rectangle.RenderTransform></Rectangle>
• PlaneProjection class applies perspective projections to XAML elements– Rotates elements about 3D coordinate axes– Applied through UIElement.Projection property
• Properties provide control over projection
Projections
Rotating Around the Y-Axis
<Image Source="..."> <Image.Projection> <PlaneProjection RotationY="45" /> </Image.Projection></Image>
Controlling "Camera" Position
<Image Source="..."> <Image.Projection> <PlaneProjection RotationY="45" GlobalOffsetY="-300" /> </Image.Projection></Image>
Moves "camera" position down300 pixels from center
• Animations vary properties of elements over time– From-to animations vary properties linearly– Key-frame animations use discrete steps
• Animation objects define animations– DoubleAnimation[UsingKeyFrames]– ColorAnimation[UsingKeyFrames]– PointAnimation[UsingKeyFrames]
• StoryBoard objects hold animation objects
Animations
From-To Animations
<Storyboard> <DoubleAnimation Storyboard.TargetName="Rect" Storyboard.TargetProperty="(Canvas.Left)" From="0" To="200" Duration="0:0:2" /></Storyboard>
Rectangle's Canvas.Left property varies linearly from 0 to 200 over 2 seconds
Key-Frame Animations
<Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Rect" Storyboard.TargetProperty="(Canvas.Left)" Duration="0:0:2"> <LinearDoubleKeyFrame KeyTime="0:0:0" Value="0" /> <LinearDoubleKeyFrame KeyTime="0:0:1" Value="50" /> <LinearDoubleKeyFrame KeyTime="0:0:2" Value="200" /> </DoubleAnimationUsingKeyFrames></Storyboard>
Canvas.Left goes from0 to 50 in first second
Canvas.Left goes from50 to 200 in second second
Triggering an Animation
// XAML<Rectangle x:Name="Rect" MouseLeftButtonDown="OnClick" ...> <Rectangle.Resources> <Storyboard x:Name="RectStoryboard"> <DoubleAnimation Storyboard.TargetName="Rect" Storyboard.TargetProperty="(Canvas.Left)" From="0" To="200" Duration="0:0:2" /> </Storyboard> </Rectangle.Resources></Rectangle>
// C#RectStoryBoard.Begin(); // Call Begin on Storyboard object
Composing Animations
<Storyboard> <DoubleAnimation Storyboard.TargetName="Rect" Storyboard.TargetProperty="(Canvas.Left)" From="0" To="200" Duration="0:0:2" /> <DoubleAnimation Storyboard.TargetName="Rect" Storyboard.TargetProperty="(Canvas.Top)" From="0" To="200" Duration="0:0:2" BeginTime="0:0:2" /></Storyboard>
Second animation beginsafter 2 seconds
First animation begins immediatelyand runs for 2 seconds
• Adds non-linear effects to animations– Bounce, oscillation, deceleration, and more
• Easing classes encapsulate effects– 11 easing classes built in (BounceEase etc.)– Create custom easing classes by implementing
IEasingFunction• Simulate physics with simple from/to
animations!
Animation Easing
Easing Classes
Class Description
BackEase Retracts the motion of an animation slightly before it begins
BounceEase Adds "bounce" to an animation
CircleEase Accelerates and/or decelerates using a circular function
CubicEase Accelerates and/or decelerates using the formula f(t) = t3
ElasticEase Adds oscillation to an animation
ExponentialEase
Accelerates and/or decelerates using an exponential formula
PowerEase Accelerates and/or decelerates using the formula f(t) = tp
QuadraticEase Accelerates and/or decelerates using the formula f(t) = t2
QuarticEase Accelerates and/or decelerates using the formula f(t) = t4
QuinticEase Accelerates and/or decelerates using the formula f(t) = t5
SineEase Accelerates and/or decelerates using a sine formula
Using BounceEase
<Storyboard x:Name="BallDrop"> <DoubleAnimation Storyboard.TargetName="Ball" Storyboard.TargetProperty="(Canvas.Top)" From="200" To="0" Duration="0:0:1"> <DoubleAnimation.EasingFunction> <BounceEase Bounces="10" Bounciness="2" EasingMode="EaseOut" /> </DoubleAnimation.EasingFunction> </DoubleAnimation></Storyboard>
• DispatcherTimer– Fires Tick events at programmable intervals– Use it to reposition objects in scene at regular
intervals• CompositionTarget.Rendering
– Per-frame events fired by rendering engine• Frequency controlled by MaxFrameRate
property– Use it to perform precision custom animations
(e.g., game loops)
Manual Animations
DispatcherTimer
private DispatcherTimer _timer; . . ._timer = new DispatcherTimer();_timer.Tick += new EventHandler(OnTimerTick);_timer.Interval = new TimeSpan(0, 0, 0, 0, 50); // 50 ms_timer.Start(); . . .private void OnTimerTick(Object sender, EventArgs e){ // TODO: Modify scene}
CompositionTarget.Rendering
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering); . . .private void CompositionTarget_Rendering(Object sender, EventArgs e){ // TODO: Modify the scene. Changes will be rendered once // the event handler returns.}
• Speeds rendering by leveraging GPU– GPU present in every Windows phone– Dedicated composition thread renders to GPU
• Transforms and projections driven by "simple" animations are automatically GPU-cached– DoubleAnimation[UsingKeyFrames]
• CacheMode="BitmapCache" caches elements that aren't auto-cached– Objects with OpacityMask or non-rectangular
clipping regions cannot be GPU-cached
GPU Acceleration
• Provides key rendering performance data– http://msdn.microsoft.com/en-us/library/
ff967560(v=vs.92).aspx– http://www.jeff.wilcox.name/2010/07/counters/
• Red counters flag potential perf problems
Frame-Rate Counter
if (System.Diagnostics.Debugger.IsAttached){ // Display the current frame rate counters. Application.Current.Host.Settings.EnableFrameRateCounter = true;
...
// Enable non-production analysis visualization mode, // which shows areas of a page that are being GPU accelerated // with a colored overlay. Application.Current.Host.Settings.EnableCacheVisualization = true;}
Enabling the Frame-Rate Counter
• Visually depicts which objects are GPU-cached
Cache Visualization
Non-GPU-Cached GPU-CachedVisualization Off
if (System.Diagnostics.Debugger.IsAttached){ // Display the current frame rate counters. Application.Current.Host.Settings.EnableFrameRateCounter = true;
...
// Enable non-production analysis visualization mode, // which shows areas of a page that are being GPU accelerated // with a colored overlay. Application.Current.Host.Settings.EnableCacheVisualization = true;}
Enabling Cache Visualization