Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 102 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
102
Dung lượng
1,55 MB
Nội dung
<Image Source="Images/BuzzAldrinOnTheMoon.png"> <Image.OpacityMask> <RadialGradientBrush> <GradientStop Offset="0" Color="White" /> <GradientStop Offset="0.8" Color="White" /> <GradientStop Offset="1" Color="Transparent" /> </RadialGradientBrush> </Image.OpacityMask> </Image> Notice that the RadialGradientBrush is opaque in the center, and continues to be opaque until a radius of 0.8, at which point the gradient goes to fully transparent at the edge of the circle. Here’s the result, a very nice effect that looks much fancier than the few lines of XAML would seem to imply: Here’s a popular technique that uses two identical elements but one of them gets both a ScaleTransform to flip it upside down, and an OpacityMask to make it fade out: <Image Source="Images/BuzzAldrinOnTheMoon.png" Stretch="None" VerticalAlignment="Top" /> <Image Source="Images/BuzzAldrinOnTheMoon.png" Stretch="None" VerticalAlignment="Top" RenderTransformOrigin="0.5 1"> <Image.RenderTransform> <ScaleTransform ScaleY="-1" /> </Image.RenderTransform> <Image.OpacityMask> <LinearGradientBrush StartPoint="0 0" EndPoint="0 1"> <GradientStop Offset="0" Color="#00000000" /> <GradientStop Offset="1" Color="#40000000" /> </LinearGradientBrush> </Image.OpacityMask> </Image> The two Image elements are the same size and aligned at the top and center. Normally the second one would be positioned on top of the other. But the second one has a RenderTransform set to a ScaleTransform that flips the image around the horizontal axis. The 189 RenderTransformOrigin is set at (0.5, 1), which is the bottom of the element. This causes the scaling to flip the image around its bottom edge. Then a LinearGradientBrush is applied to the OpacityMask property to make the reflected image fade out: Notice that the GradientStop values apply to the unreflected image, so that full transparency (the #00000000 value) seems to be at the top of the picture and then is reflected to the bottom of the composite display. It is often little touches like these that make a program’s visuals pop out just a little more and endear themselves to the user.But indiscriminate use of OpacityMask—particularly in combination with complex animations—is discouraged because it sometimes tends to cripple performance. The general rule is: Only use OpacityMask if the effect is really, really cool. Non-Tiled Tile Brushes You’ve seen examples of SolidColorBrush, LinearGradientBrush, and RadialGradientBrush. This class hierarchy is complete from Brush on down: Object DependencyObject (abstract) Brush (abstract) SolidColorBrush (sealed) GradientBrush (abstract) LinearGradientBrush (sealed) 190 RadialGradientBrush (sealed) TileBrush (abstract) ImageBrush (sealed) VideoBrush (sealed) ImplicitInputBrush (sealed) However, the only other brush supported under Windows Phone 7 is ImageBrush, and although it derives from TileBrush, you can’t create a tiled pattern with it. (You can in the Windows Presentation Foundation, and perhaps someday in Silverlight.) Basically, ImageBrush lets you set any property of type Brush to a bitmap. Here’s ImageExperiment again but with the Image element replaced with an ImageBrush set to the Background property of the content grid: <Grid x:Name="ContentGrid" Grid.Row="1" Margin="12,0,12,0"> <Grid.Background> <ImageBrush ImageSource="Images/BuzzAldrinOnTheMoon.png" /> </Grid.Background> </Grid> Like Image, TileBrush defines a Stretch property, but the default value is Fill, so the image fills the area without regard to aspect ratio. 191 Chapter 9 The Intricacies of Layout One of the most important classes in all of Silverlight is Panel—the class that plays a starring role in the Silverlight layout system. You might expect such a crucial class to define many properties and events, but Panel defines only three properties on its own: • Background of type Brush • Children of type UIElementCollection • IsItemsHost of type bool The first one is simple, and the third one is get-only and involves its role in ListBox and related classes. The big one is the Children property. In the previous chapter you saw that the Border class defines a property named Child of type UIElement. This Children property defined by the Panel is of type UIElementCollection. Huge difference! The Border doesn’t have a whole lot of decision-making regarding its single child. The child element is inside the Border and that’s about it. But a panel can host multiple children, and it can do this in a variety of ways. Perhaps the panel aligns the children in a stack, or a grid, or perhaps it docks the children on its edges, or puts them in a circle, or displays them like a fanned deck of cards, or arranges them in a carousel. For this reason, the Panel class itself is abstract. This class hierarchy is complete from Panel onwards: Object DependencyObject (abstract) UIElement (abstract) FrameworkElement (abstract) Panel (abstract) Canvas InkPresenter (sealed) Grid StackPanel VirtualizingPanel (abstract) VirtualizingStackPanel PanoramaPanel 192 MapLayerBase (abstract) MapLayer (sealed) The three standard types of panels provided by Silverlight for Windows Phone are StackPanel (probably the simplest kind of panel), Grid (which is the first choice for most routine layout), and Canvas, which should be ignored for most routine layout jobs, but has some special characteristics that make it handy sometimes. The Silverlight for Windows Phone Toolkit includes a WrapPanel, which is rather similar to the right side of Windows Explorer. I’ll show you a sample program using InkPresenter in the next chapter. The VirtualizingPanel option is discussed in Chapter 17 in connection with items controls, and the others (as their names suggest) are for specialized purposes in connection with the Panorama and Map controls. You’ve already seen the Grid and StackPanel in the standard MainPage.xaml, and you’ve probably deduced that panels can be nested. Panels are the primary architectural elements of the Silverlight page. You can also write your own panels. I’ll show you the basics in this chapter, and then more sophisticated panels in the chapters ahead. The Single-Cell Grid A Grid is generally arranged in rows and columns, but you’ve seen in previous chapters that you can put multiple children in a single-cell Grid. Here’s a simple example for reference purposes: Silverlight Project: GridWithFourElements File: MainPage.xaml (excerpt) <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <TextBlock Text="TextBlock aligned at right bottom" HorizontalAlignment="Right" VerticalAlignment="Bottom" /> <Image Source="Images/BuzzAldrinOnTheMoon.png" /> <Ellipse Stroke="{StaticResource PhoneAccentBrush}" StrokeThickness="24" /> <TextBlock Text="TextBlock aligned at left top" HorizontalAlignment="Left" VerticalAlignment="Top" /> </Grid> 193 All four elements are given the entire content area in which to reside: With regard to size, the elements here are all a little different. The sizes of the two TextBlock elements are governed by the text being displayed and the size of the font. The Image element displays the bitmap in the maximum size allowed by the dimensions of the Grid but maintaining the proper aspect rate. The Ellipse just sprawls out as much as it can. The elements overlap in the order in which they appear in the markup, which is the order that they are added to the Children collection of the Grid. I’ve set the SupportedOrientations property on the Page to PortraitOrLandscape so you can turn the phone sideways and the elements shift around: 194 The StackPanel Stack Here are the same four elements in a StackPanel, which is nested in the content grid: Silverlight Project: StackPanelWithFourElements File: MainPage.xaml (excerpt) <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <StackPanel Name="stackPanel" Orientation="Vertical"> <TextBlock Text="TextBlock aligned at right bottom" HorizontalAlignment="Right" VerticalAlignment="Bottom" /> <Image Source="Images/BuzzAldrinOnTheMoon.png" /> <Ellipse Stroke="{StaticResource PhoneAccentBrush}" StrokeThickness="12" /> <TextBlock Text="TextBlock aligned at left top" HorizontalAlignment="Left" VerticalAlignment="Top" /> </StackPanel> </Grid> By default, the StackPanel arranges its children in a stack from top to bottom. The children do not overlap: 195 The text displayed by the two TextBlock elements now seems a little peculiar: The first TextBlock is at the top of the display because that’s the first one in the Children collection. The HorizontalAlignment property moves it over to the right, but the VerticalAlignment property (which indicates Bottom) is obviously being ignored, and similarly for the other TextBlock. The width of the Image element occupies the full width of the StackPanel. It still has the correct aspect ratio, and now only requires enough vertical space to accommodate its height. Both the TextBlock and Image elements only occupy the minimum vertical space that they require, and the Ellipse… well, the Ellipse has totally disappeared. You might find that shocking, but reasonable. The Ellipse doesn’t really require any vertical space at all, and that’s exactly what it’s received. (If you set the Height property of Ellipse to a positive number, you’ll bring it back into view.) Changing the orientation of the phone provides the Image with a greater width that it matches with a height that preserves the aspect ratio of the bitmap, but in doing so pushes most of the bitmap off the screen, together with the second TextBlock: As you know, the ability of the page to respond to portrait and landscape orientation changes is governed by the SupportedOrientations property of the PhoneApplicationPage class. The property is set to a member of the SupportedPageOrientation enumeration. PhoneApplicationPage defines another property named Orientation which is set to a member of the PageOrientation enumeration to indicate whether the orientation of the phone is currently portrait or landscape. The StackPanel has its own Orientation property, but it has nothing to do with page orientation. The Orientation property of StackPanel is set to a member of the Orientation enumeration, either Horizontal or Vertical. The default is Vertical, but the StackPanelWithFourElements program toggles the StackPanel orientation when you tap the screen. Here’s the code to do it: 196 Silverlight Project: StackPanelWithFourElements File: MainPage.xaml.cs (excerpt) protected override void OnManipulationStarted(ManipulationStartedEventArgs args) { stackPanel.Orientation = stackPanel.Orientation == System.Windows.Controls.Orientation.Vertical ? System.Windows.Controls.Orientation.Horizontal : System.Windows.Controls.Orientation.Vertical; args.Complete(); args.Handled = true; base.OnManipulationStarted(args); } The Orientation enumeration has to be fully qualified or the compiler thinks you’re referring to the Orientation property defined by PhoneApplicationPage. One tap and the elements are arranged from left to right: The HorizontalAlignment of the first TextBlock is now ignored, and the VerticalAlignment puts it down at the bottom. The Image gets such a big height that most of it is off screen. We can get a little better view (including the second TextBlock) by turning the phone sideways: 197 The StackPanel occupies the full interior of the content grid, even if that that’s more than what its children require. You can easily verify this by setting a Background on the StackPanel. The StackPanel fills its parent container because the default values of the HorizontalAlignment and VerticalAlignment properties are the default values of Stretch. You can set other HorizontalAlignment or VerticalAlignment properties on the StackPanel to force it to use only as much space as necessary, and position it within the content grid. Here’s a Background of Pink and a VerticalAlignment property of Center: In this particular program, the HorizontalAlignment property of the StackPanel has no effect. 198 [...]... partial class MainPage : PhoneApplicationPage { Brush accentBrush; public MainPage() { 208 InitializeComponent(); accentBrush = this.Resources["PhoneAccentBrush"] as Brush; // Get all assemblies List assemblies = new List(); assemblies.Add(Assembly.Load("System .Windows" )); assemblies.Add(Assembly.Load("Microsoft .Phone" )); assemblies.Add(Assembly.Load("Microsoft .Phone. Controls")); assemblies.Add(Assembly.Load("Microsoft .Phone. Controls.Maps"));... /> 221 Notice I’ve removed the Margin on the content... partial class MainPage : PhoneApplicationPage { public MainPage() { InitializeComponent(); } void OnCanvasSizeChanged(object sender, SizeChangedEventArgs args) { canvas.Children.Clear(); for (double y = 0; y < args.NewSize.Height; y += 75 ) for (double x = 0; x < args.NewSize.Width; x += 75 ) { 2 23 Ellipse ellipse = new Ellipse { Width = 100, Height = 100, Stroke = this.Resources["PhoneAccentBrush"] as... most important Silverlight programming skills you can acquire The layout system is very powerful, but for the uninitiated, it can also seem quite strange Layout in Silverlight is a two-pass process starting at the top of the visual tree and working down through all the elements’ children In a Silverlight phone application, it begins with the 211 PhoneApplicationFrame, then the PhoneApplicationPage, then... containing a vertical StackPanel, but it fills up that StackPanel entirely in code Using reflection, the code-behind file obtains all the public classes exposed by the System .Windows, Microsoft .Phone, Microsoft .Phone. Controls, and Microsoft .Phone. Controls.Maps assemblies, and lists them in a class hierarchy In preparation for this job, the XAML file contains an empty StackPanel identified by name: Silverlight... elements towards the bottom (or right) won’t be displayed If you fear that the phone s screen is not large enough to fit all the children of your StackPanel, you can put the StackPanel in a ScrollViewer, a control that determines how large its content needs to be, and provides a scrollbar or two Actually, on Windows Phone 7, the scrollbars are more virtual than real You don’t actually scroll the ScrollViewer... Value="Wrap" /> 03; I consider that a conversation by telephone — when you are simply sitting by and not taking any part in that conversation — is one of the solemnest... why, but they do So I touched the bell, and this talk ensued: — 03; Central Office. [Gruffly.] Hello! 03; I. Is it the Central Office? … ... HorizontalAlignment="Right" VerticalAlignment="Bottom" /> You’ll discover that this program displays the elements the same way as the earlier... Property="Height" Value="100" /> . only other brush supported under Windows Phone 7 is ImageBrush, and although it derives from TileBrush, you can’t create a tiled pattern with it. (You can in the Windows Presentation Foundation,. code-behind file obtains all the public classes exposed by the System .Windows, Microsoft .Phone, Microsoft .Phone. Controls, and Microsoft .Phone. Controls.Maps assemblies, and lists them in a class hierarchy stackPanel.Orientation = stackPanel.Orientation == System .Windows. Controls.Orientation.Vertical ? System .Windows. Controls.Orientation.Horizontal : System .Windows. Controls.Orientation.Vertical; args.Complete();