Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 132 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
132
Dung lượng
1,76 MB
Nội dung
Chapter 34: Windows Presentation Foundation 1179 Run this example and experiment with resizing content. Note that the further up the stacking order a control is, the more priority is given to its space. By shrinking the window, the fifth Border control can quickly be completely obscured by controls further up the stacking order. Be careful when using DockPanel control layout to avoid this, perhaps by setting minimum dimensions for the window. Grid Grid controls can have multiple rows and columns that you can use to lay out child controls. You have used Grid controls several times already in this chapter, but in all cases you used a Grid with a single row and a single column. To add more rows and columns, you must use the RowDefinitions and ColumnDefinitions properties, which are collections of RowDefinition and ColumnDefinition objects, respectively, and are specified using property element syntax: < Grid > < Grid.RowDefinitions > < RowDefinition / > < RowDefinition / > < /Grid.RowDefinitions > < Grid.ColumnDefinitions > < ColumnDefinition / > < ColumnDefinition / > < /Grid.ColumnDefinitions > < /Grid > This code defines a Grid control with three rows and two columns. Note that no extra information is required here; with this code, each row and column is dynamically resized automatically as the Grid control resizes. Each row will be a third of the height of the Grid , and each column will be half the width. You can display lines between cells in a Grid by setting the Grid.ShowGridlines property to true . You can control the resizing with Width , Height , MinWidth , MaxWidth , MinHeight , and MaxHeight properties. For example, setting the Width property of a column ensures that the column stays at that width. You can also set the Width property of a column to * , which means “ fill the remaining space after calculating the width of all other columns. ” This is actually the default. When you have multiple columns with a Width of * , then the remaining space is divided between them equally. The * value can also be used with the Height property of rows. The other possible value for Height and Width is Auto , which sizes the row or column according to its content. You can also use GridSplitter controls to enable users to customize the dimensions of rows and columns by clicking and dragging. Child controls of a Grid control can use the attached Grid.Column and Grid.Row properties to specify what cell they are contained in. Both these properties default to 0, so if you omit them, then the child control is placed in the top - left cell. Child controls can also use Grid.ColumnSpan and Grid.RowSpan to be positioned over multiple cells in a table, where the upper - left cell is specified by Grid.Column and Grid.Row . Figure 34 - 13 shows a Grid control containing multiple ellipses and a GridSplitter with the window resized to two sizes. c34.indd 1179c34.indd 1179 3/25/08 12:37:09 PM3/25/08 12:37:09 PM 1180 Part V: Additional Techniques The code used here is as follows: < Grid Background=”AliceBlue” > < Grid.ColumnDefinitions > < ColumnDefinition MinWidth=”100” MaxWidth=”200” / > < ColumnDefinition MaxWidth=”100” / > < ColumnDefinition Width=”50” / > < ColumnDefinition Width=”*” / > < /Grid.ColumnDefinitions > < Grid.RowDefinitions > < RowDefinition Height=”50” / > < RowDefinition MinHeight=”100” / > < RowDefinition / > < /Grid.RowDefinitions > < Ellipse Grid.Row=”0” Grid.Column=”0” Fill=”BlanchedAlmond” Stroke=”Black” / > < Ellipse Grid.Row=”0” Grid.Column=”1” Fill=”BurlyWood” Stroke=”Black” / > < Ellipse Grid.Row=”0” Grid.Column=”2” Fill=”BlanchedAlmond” Stroke=”Black” / > < Ellipse Grid.Row=”0” Grid.Column=”3” Fill=”BurlyWood” Stroke=”Black” / > < Ellipse Grid.Row=”1” Grid.Column=”0” Fill=”BurlyWood” Stroke=”Black” / > < Ellipse Grid.Row=”1” Grid.Column=”1” Fill=”BlanchedAlmond” Stroke=”Black” / > < Ellipse Grid.Row=”1” Grid.Column=”2” Fill=”BurlyWood” Stroke=”Black” / > < Ellipse Grid.Row=”1” Grid.Column=”3” Fill=”BlanchedAlmond” Stroke=”Black” / > < Ellipse Grid.Row=”2” Grid.Column=”0” Fill=”BlanchedAlmond” Stroke=”Black” / > < Ellipse Grid.Row=”2” Grid.Column=”1” Fill=”BurlyWood” Stroke=”Black” / > < Ellipse Grid.Row=”2” Grid.Column=”2” Fill=”BlanchedAlmond” Stroke=”Black” / > < Ellipse Grid.Row=”2” Grid.Column=”3” Fill=”BurlyWood” Stroke=”Black” / > < Ellipse Grid.Row=”2” Grid.Column=”2” Grid.ColumnSpan=”2” Fill=”Gold” Stroke=”Black” Height=”50”/ > < GridSplitter Grid.RowSpan=”3” Width=”10” BorderThickness=”2” > < GridSplitter.BorderBrush > < SolidColorBrush Color=”Black” / > < /GridSplitter.BorderBrush > < /GridSplitter > < /Grid > Figure 34-13 c34.indd 1180c34.indd 1180 3/25/08 12:37:10 PM3/25/08 12:37:10 PM Chapter 34: Windows Presentation Foundation 1181 This code uses various combinations of properties on the row and column definitions to achieve an interesting effect when you resize the display, so it ’ s worth testing for yourself. First, consider the rows. The top row has a fixed height of 50 pixels, the second row has a minimum height of 100, and the third row fills the remaining space. This means that if the Grid has a height of less than 150 pixels, then the third row will not be visible. When the Grid has a height of between 150 and 250 pixels, only the size of the third row will change, from 0 to 100 pixels. This is because the remaining space is calculated as the total height minus the combined heights of rows that have a fixed height. This remaining space is allocated between the second and third rows, but because the second row has a minimum height of 100 pixels, it will not change its height until the total height of the Grid reaches 250 pixels. Finally, when the height of the Grid is greater than 250, both the second and third rows will share the remaining space, so their height will be both equal to and greater than 100 pixels. Next, look at the columns. Only the third column has a fixed size, of 50 pixels. The first and second columns share up to a maximum of 300 pixels. The fourth column will therefore be the only one to increase in size when the total width of the Grid control exceeds 550 pixels. To work this out for yourself, consider how many pixels are available to the columns and how they are distributed. First, 50 pixels are allocated to the third column, leaving 500 for the rest of the columns. The third column has a maximum width of 100 pixels, leaving 400 between the first and fourth columns. The first column has a maximum width of 200, so even if the width increases beyond this point, it will not consume any more space. Instead, the fourth column will increase in size. Note two additional points in this example. First, the final ellipse defined spans the third and fourth columns to illustrate Grid.ColumnSpan . Second, a GridSplitter is provided to enable resizing of the first and second columns. However, once the total width of the Grid control exceeds 550 pixels, this GridSplitter will not be able to size these columns, as neither the first nor the second column can increase in size. The GridSplitter control is useful, but it has a very dull appearance. This is one control that really needs to be styled, or at least made invisible by setting its Background property to Transparent , for you to make the most of it. If you have multiple Grid controls in a window, you can also define shared size groups for rows or columns by using the ShareSizeGroup property in row and/or column definitions, which you just set to a string identifier of your choice. For example, if a column in a shared size group changes in one Grid control, then a column in another Grid control in the same size group will change to match this size. You can enable or disable this functionality through the Grid.IsSharedSizeScope property. StackPanel After the complexity of Grid , you may be relieved to discover that StackPanel is a relatively simple layout control. You can think of StackPanel as being a slimmed down version of DockPanel , where the edge to which child controls are docked is fixed for those controls. The other difference between these controls is that the last child control of a StackPanel doesn ’ t fill the remaining space. However, controls will, by default, stretch to the edges of the StackPanel control. The direction in which controls are stacked is determined by three properties. Orientation can be set to Horizontal or Vertical , and HorizontalAlignment and VerticalAlignement can be used to determine whether control stacks are positioned next to the top, bottom, left, or right edge of the StackPanel . You can even make the stacked controls stack at the center of the StackPanel using the Center value for the alignment property you use. c34.indd 1181c34.indd 1181 3/25/08 12:37:10 PM3/25/08 12:37:10 PM 1182 Part V: Additional Techniques Figure 34 - 14 shows two StackPanel controls, each of which contains three buttons. The StackPanel controls are positioned using a Grid control with two rows and one column. Figure 34-14 The code used here is as follows: < Grid Background=”AliceBlue” > < Grid.RowDefinitions > < RowDefinition / > < RowDefinition / > < /Grid.RowDefinitions > < StackPanel Grid.Row=”0” > < Button > Button1 < /Button > < Button > Button2 < /Button > < Button > Button3 < /Button > < /StackPanel > < StackPanel Grid.Row=”1” Orientation=”Horizontal” > < Button > Button1 < /Button > < Button > Button2 < /Button > < Button > Button3 < /Button > < /StackPanel > < /Grid > When you use StackPanel layout, you often need to add scroll bars so that it is possible to view all the controls contained in the StackPanel . This is another area where WPF does a lot of the heavy lifting for you. You can use the ScrollViewer control to achieve this — simply enclose the StackPanel in this control: < Grid Background=”AliceBlue” > < Grid.RowDefinitions > < RowDefinition / > < RowDefinition / > < /Grid.RowDefinitions > < ScrollViewer > < StackPanel Grid.Row=”0” > < Button > Button1 < /Button > < Button > Button2 < /Button > c34.indd 1182c34.indd 1182 3/25/08 12:37:11 PM3/25/08 12:37:11 PM Chapter 34: Windows Presentation Foundation 1183 < Button > Button3 < /Button > < /StackPanel > < /ScrollViewer > < StackPanel Grid.Row=”1” Orientation=”Horizontal” > < Button > Button1 < /Button > < Button > Button2 < /Button > < Button > Button3 < /Button > < /StackPanel > < /Grid > You can use more complicated techniques to scroll in different ways, or to scroll programmatically, but often this is all you need to do. WrapPanel WrapPanel is essentially an extended version of StackPanel where controls that “ don ’ t fit ” are moved to additional rows (or columns). Figure 34 - 15 shows a WrapPanel control containing multiple shapes, with the window resized to two sizes. Figure 34-15 An abbreviated version of the code to achieve this is shown here: < WrapPanel Background=”AliceBlue” > < Rectangle Fill=”#FF000000” Height=”50” Width=”50” Stroke=”Black” RadiusX=”10” RadiusY=”10” / > < Rectangle Fill=”#FF111111” Height=”50” Width=”50” Stroke=”Black” RadiusX=”10” RadiusY=”10” / > < Rectangle Fill=”#FF222222” Height=”50” Width=”50” Stroke=”Black” RadiusX=”10” RadiusY=”10” / > < Rectangle Fill=”#FFFFFFFF” Height=”50” Width=”50” Stroke=”Black” RadiusX=”10” RadiusY=”10” / > < /WrapPanel > c34.indd 1183c34.indd 1183 3/25/08 12:37:11 PM3/25/08 12:37:11 PM 1184 Part V: Additional Techniques WrapPanel controls are a great way to create a dynamic layout that enables users to control exactly how content should be viewed. Control Styling One of the best features of WPF is the complete control it provides designers over the look and feel of user interfaces. Central to this is the ability to style controls however you want, in two or three dimensions. Until now, you have been using the basic styling for controls that is supplied with .NET 3.5, but the actual possibilities are endless. This section describes two basic techniques: Styles : Sets of properties that are applied to a control as a batch Templates : The controls that are used to build the display for a control There is some overlap here, as styles can contain templates. Styles WPF controls have a property called Style (inherited from FrameworkElement ) that can be set to an instance of the Style class. The Style class is quite complex and is capable of advanced styling functionality, but at its heart it is essentially a set of Setter objects. Each Setter object is responsible for setting the value of a property according to its Property property (the name of the property to set) and its Value property (the value to set the property to). You can either fully qualify the name you use in Property to the control type (for example, Button.Foreground ) or you can set the TargetType property of the Style object (for example, Button ) so that it is capable of resolving property names. The following code, then, shows how to use a Style object to set the Foreground property of a Button control: < Button > Click me! < Button.Style > < Style TargetType=”Button” > < Setter Property=”Foreground” > < Setter.Value > < SolidColorBrush Color=”Purple” / > < /Setter.Value > < /Setter > < /Style > < /Button.Style > < /Button > ❑ ❑ c34.indd 1184c34.indd 1184 3/25/08 12:37:11 PM3/25/08 12:37:11 PM Chapter 34: Windows Presentation Foundation 1185 Obviously, in this case it would be far easier simply to set the Foreground property of the button in the usual way. Styles become much more useful when you turn them into resources, because resources can be reused. You will learn how to do this later in the chapter. Templates Controls are constructed using templates, which you can customize. A template consists of a hierarchy of controls used to build the display of a control, which may include a content presenter for controls such as buttons that display content. The template of a control is stored in its Template property, which is an instance of the ControlTemplate class. The ControlTemplate class includes a TargetType property that you can set to the type of control for which you are defining a template, and it can contain a single control. This control can be a container such as Grid , so this doesn ’ t exactly limit what you can do. Typically, you set the template for a class by using a style. This simply involves providing controls to use for the Template property in the following way: < Button > Click me! < Button.Style > < Style TargetType=”Button” > < Setter Property=”Template” > < Setter.Value > < ControlTemplate TargetType=”Button” > < /ControlTemplate > < /Setter.Value > < /Setter > < /Style > < /Button.Style > < /Button > Some controls may require more than one template. For example, CheckBox controls use one template for a check box ( CheckBox.Template ) and one template to output text next to the check box ( CheckBox.ContentTemplate ). Templates that require content presenters can include a ContentPresenter control at the location where you want to output content. Some controls, in particular those that output collections of items, use alternative techniques, which aren ’ t covered in this chapter. Again, replacing templates is most useful when combined with resources. However, as control styling is a very common technique, it is worth looking at how to do it in a Try It Out. c34.indd 1185c34.indd 1185 3/25/08 12:37:11 PM3/25/08 12:37:11 PM 1186 Part V: Additional Techniques Try It Out Using Styles and Templates 1. Create a new WPF application called Ch34Ex03 and save it in the directory C:\BegVCSharp\Chapter34. 2. Modify the code in Window1.xaml as follows: < Window x:Class=”Ch34Ex03.Window1” xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” Title=”Nasty Button” Height=”150” Width=”550” > < Grid Background=”Black” > < Button Margin=”20” Click=”Button_Click” > Would anyone use a button like this? < Button.Style > < Style TargetType=”Button” > < Setter Property=”FontSize” Value=”18” / > < Setter Property=”FontFamily” Value=”arial” / > < Setter Property=”FontWeight” Value=”bold” / > < Setter Property=”Foreground” > < Setter.Value > < LinearGradientBrush StartPoint=”0.5,0” EndPoint=”0.5,1” > < LinearGradientBrush.GradientStops > < GradientStop Offset=”0.0” Color=”Purple” / > < GradientStop Offset=”0.5” Color=”Azure” / > < GradientStop Offset=”1.0” Color=”Purple” / > < /LinearGradientBrush.GradientStops > < /LinearGradientBrush > < /Setter.Value > < /Setter > < Setter Property=”Template” > < Setter.Value > < ControlTemplate TargetType=”Button” > < Grid > < Grid.ColumnDefinitions > < ColumnDefinition Width=”50” / > < ColumnDefinition / > < ColumnDefinition Width=”50” / > < /Grid.ColumnDefinitions > < Grid.RowDefinitions > < RowDefinition MinHeight=”50” / > < /Grid.RowDefinitions > < Ellipse Grid.Column=”0” Height=”50” > < Ellipse.Fill > < RadialGradientBrush > < RadialGradientBrush.GradientStops > < GradientStop Offset=”0.0” Color=”Yellow” / > < GradientStop Offset=”1.0” Color=”Red” / > < /RadialGradientBrush.GradientStops > < /RadialGradientBrush > < /Ellipse.Fill > < /Ellipse > c34.indd 1186c34.indd 1186 3/25/08 12:37:12 PM3/25/08 12:37:12 PM Chapter 34: Windows Presentation Foundation 1187 < Grid Grid.Column=”1” > < Rectangle RadiusX=”10” RadiusY=”10” > < Rectangle.Fill > < RadialGradientBrush > < RadialGradientBrush.GradientStops > < GradientStop Offset=”0.0” Color=”Yellow” / > < GradientStop Offset=”1.0” Color=”Red” / > < /RadialGradientBrush.GradientStops > < /RadialGradientBrush > < /Rectangle.Fill > < /Rectangle > < ContentPresenter Margin=”20,0,20,0” HorizontalAlignment=”Center” VerticalAlignment=”Center” / > < /Grid > < Ellipse Grid.Column=”2” Height=”50” > < Ellipse.Fill > < RadialGradientBrush > < RadialGradientBrush.GradientStops > < GradientStop Offset=”0.0” Color=”Yellow” / > < GradientStop Offset=”1.0” Color=”Red” / > < /RadialGradientBrush.GradientStops > < /RadialGradientBrush > < /Ellipse.Fill > < /Ellipse > < /Grid > < /ControlTemplate > < /Setter.Value > < /Setter > < /Style > < /Button.Style > < /Button > < /Grid > < /Window > 3. Modify the code in Window1.xaml.cs as follows: public partial class Window1 : Window { private void Button_Click(object sender, RoutedEventArgs e) { MessageBox.Show(“Button clicked.”); } } 4. Run the application and click once on the button. Figure 34 - 16 shows the result. c34.indd 1187c34.indd 1187 3/25/08 12:37:12 PM3/25/08 12:37:12 PM 1188 Part V: Additional Techniques How It Works First, let me apologize for the truly nasty - looking button shown in this example. However, aesthetic considerations aside, this example does show that you can completely change how a button looks in WPF without a lot of effort. In changing the button template, though, note that the functionality of the button remains unchanged. That is, you can click on the button and respond to that click in an event handler. You probably noticed that certain things you associate with Windows buttons aren ’ t implemented in the template used here. In particular, there is no visual feedback when you roll over the button or when you click it. This button also looks exactly the same whether it has focus or not. To achieve these effects you need to learn about triggers, which are the subject of the next section. Before doing that, though, consider the example code in a little more detail, focusing on styles and templates and looking at how the template was created. The code starts with ordinary code that you would use to display a Button control: < Button Margin=”20” Click=”Button_Click” > Would anyone use a button like this? This provides basic properties and content for the button. Next, the Style property is set to a Style object, which begins by setting three simple font properties of the Button control: < Button.Style > < Style TargetType=”Button” > < Setter Property=”FontSize” Value=”18” / > < Setter Property=”FontFamily” Value=”arial” / > < Setter Property=”FontWeight” Value=”bold” / > Next, the Button.Foreground property is set using property element syntax because a brush is used: < Setter Property=”Foreground” > < Setter.Value > < LinearGradientBrush StartPoint=”0.5,0” EndPoint=”0.5,1” > < LinearGradientBrush.GradientStops > < GradientStop Offset=”0.0” Color=”Purple” / > < GradientStop Offset=”0.5” Color=”Azure” / > Figure 34-16 c34.indd 1188c34.indd 1188 3/25/08 12:37:12 PM3/25/08 12:37:12 PM [...]... Fill=”#FFFFFFFF” Stretch=”Fill” Stroke=”{x:Null}” Margin=”0,0,35.218,-0.077” Data=”F1 M 110. 5,51 L123.16457,51 C116.5986, 76.731148 115.63518,132.69684 121.63533,149.34013 133.45299, 182.12018 152.15821,195.69803 161.79765,200.07669 L 110. 5,200 C103.59644, 200 98,194.40356 98,187.5 L98,63.5 C98,56.596439 103 .59644,51 110. 5,51 z”> ... Storyboard.TargetProperty=”Center” RepeatBehavior=”Forever”> Point values are specified in... a new user control to the application called Card and modify the code in Card.xaml as follows: . Width=”50” Stroke=”Black” RadiusX= 10 RadiusY= 10 / > < Rectangle Fill=”#FF111111” Height=”50” Width=”50” Stroke=”Black” RadiusX= 10 RadiusY= 10 / > < Rectangle Fill=”#FF222222”. Width=”50” Stroke=”Black” RadiusX= 10 RadiusY= 10 / > < Rectangle Fill=”#FFFFFFFF” Height=”50” Width=”50” Stroke=”Black” RadiusX= 10 RadiusY= 10 / > < /WrapPanel > . KeyTime=”00:00:01” Value= 100 ,50” / > < LinearPointKeyFrame KeyTime=”00:00:02” Value= 100 ,100 ” / > < LinearPointKeyFrame KeyTime=”00:00:03” Value=”50 ,100 ” / > < LinearPointKeyFrame