Pro C# 2008 and the .NET 3.5 Platform, Fourth Edition phần 9 doc

140 382 0
Pro C# 2008 and the .NET 3.5 Platform, Fourth Edition phần 9 doc

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Figure 29-23. Grid types containing splitters ■Source Code The GridWithSplitter.xaml file can be found under the Chapter 29 subdirectory. Positioning Content Within DockPanel Panels DockPanel is typically used as a master panel that contains any number of additional panels for grouping of related content. DockPanels make use of attached property syntax as seen with the Canvas type, to control where their upper-left corner (the default) will attach itself within the panel. Here is a very simple DockPanel definition, which results in the output shown in Figure 29-24: <DockPanel LastChildFill ="True"> <! Dock items to the panel > <Label DockPanel.Dock ="Top" Name="lblInstruction" FontSize="15">Enter Car Information</Label> <Label DockPanel.Dock ="Left" Name="lblMake">Make</Label> <Label DockPanel.Dock ="Right" Name="lblColor">Color</Label> <Label DockPanel.Dock ="Bottom" Name="lblPetName">Pet Name</Label> <Button Name="btnOK">OK</Button> </DockPanel> Figure 29-24. A simple DockPanel ■Note If you add multiple elements to the same side of a DockPanel, they will be stacked along the specified edge in the order that they are declared. The benefit of using DockPanel types is that as the user resizes the window, each element remains “connected” to the specified side of the panel (via DockPanel.Dock). Also notice that the opening <DockPanel> element sets the LastChildFill attribute to true. Given that the Button type has not specified any DockPanel.Dock value, it will therefore be stretched within the remaining space. CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1092 8849CH29.qxd 10/16/07 12:17 PM Page 1092 www.free-ebooks-download.org Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com ■Source Code The SimpleDockPanel.xaml file can be found under the Chapter 29 subdirectory. Enabling Scrolling for Panel Types It is worth pointing out the WPF supplies a <ScrollViewer> type, which provides automatic scrolling behaviors for nested panel types: <ScrollViewer> <StackPanel> <Button Content ="First" Background = "Green" Height ="40"/> <Button Content ="Second" Background = "Red" Height ="40"/> <Button Content ="Third" Background = "Pink" Height ="40"/> <Button Content ="Fourth" Background = "Yellow" Height ="40"/> <Button Content ="Fifth" Background = "Blue" Height ="40"/> </StackPanel> </ScrollViewer> The result of the previous XAML definition is shown in Figure 29-25. Figure 29-25. Working with the ScrollViewer type ■Source Code The ScrollViewer.xaml file can be found under the Chapter 29 subdirectory. As you would expect, each panel provides numerous members that allow you to fine-tune con- tent placement. On a related note, WPF controls all support two properties of interest ( Padding and Margin) that allow the control itself to inform the panel how it wishes to be treated. Specifically, the Padding property controls how much extra space should surround the interior control, while Margin controls the extra space around the exterior of a control. This wraps up our look at the major panel types of WPF, and the various ways they position their content. Next, we will see an example using nested panels to create a layout system for a main window. To do so, we will enhance the functionality of the TextControls project (e.g., the spell- checker app) to support a main menu, a status bar, and a toolbar. Building a Window’s Frame Using Nested Panels This updated version of the application (which we will assume is a new Visual Studio 2008 WPF Application project named MySpellChecker) will be extended and finalized over the pages to come, so for the time being, you will construct the core layout and base functionality. Our goal is to construct a layout where the main window has a topmost menu system, a tool- bar, and a status bar mounted on the bottom of the window. The status bar will contain a pane to hold text prompts that are displayed when the user selects a menu item (or toolbar button), while CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1093 8849CH29.qxd 10/16/07 12:17 PM Page 1093 www.free-ebooks-download.org Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com the menu system and toolbar will offer UI triggers to close the application and display spelling sug- gestions in an Expander widget. Figure 29-26 shows the initial layout we are shooting for, displaying spelling suggestions for “XAML.” Figure 29-26. Using nested panels to establish a window’s UI Notice that our two toolbar buttons are not supporting an expected image, but a simple text value. While this would not be sufficient for a production-level application, assigning images to toolbar buttons typically involves using embedded resources, a topic that you will examine in Chapter 30 (so text data will do for now). Also note that as the mouse button is placed over the Check button, the mouse cursor changes and the single pane of the status bar displays a useful UI message. To begin building this UI, update the initial XAML definition for your Window type to make use of a <DockPanel> child element, rather than the default <Grid>: <Window x:Class="MySpellChecker.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MySpellChecker" Height="331" Width="508" WindowStartupLocation ="CenterScreen" > <! This panel establishes the content for the window > <DockPanel> </DockPanel> </Window> Building the Menu System Menu systems in WPF are represented by the Menu type, which maintains a collection of MenuItem objects. When building a menu system in XAML, each MenuItem may handle various events, most notably Click, which occurs when the end user selects a subitem. In our example, we will build two topmost menu items (File and Tools), which expose Exit and Spelling Hints subitems (respectively). In addition to handling the Click event for each subitem, we will also handle the MouseEnter and MouseExit events, which will be used to set the status bar text in a later step. Add the following markup within your <DockPanel> scope: CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1094 8849CH29.qxd 10/16/07 12:17 PM Page 1094 www.free-ebooks-download.org Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com <! Doc menu system on the top > <Menu DockPanel.Dock ="Top" HorizontalAlignment="Left" Background="White" BorderBrush ="Black"> <MenuItem Header="_File" Click ="FileExit_Click" > <Separator/> <MenuItem Header ="_Exit" MouseEnter ="MouseEnterExitArea" MouseLeave ="MouseLeaveArea" Click ="FileExit_Click"/> </MenuItem> <MenuItem Header="_Tools"> <MenuItem Header ="_Spelling Hints" MouseEnter ="MouseEnterToolsHintsArea" MouseLeave ="MouseLeaveArea" Click ="ToolsSpellingHints_Click"/> </MenuItem> </Menu> Notice that we have docked the menu system to the top of the DockPanel. As well, the <Separator> element has been used to insert a thin horizontal line in the menu system, directly before the Exit option. Also notice that the Header values for each MenuItem contain an embedded underbar token (for example, _Exit). This is used to establish which letter will be underlined when the end user presses the Alt key (for keyboard shortcuts). The complete the menu system definition, we now need to implement the various event han- dlers. First, we have the File ➤ Exit handler, FileExit_Click(), which will simply terminate the application via Application.Current.Shutdown(). The MouseEnter and MouseExit event handlers for each subitem will eventually update our status bar; however, for now, we will simply provide shells. Finally, the ToolsSpellingHints_Click() handler for the Tools ➤ Spelling Hints menu item will also be a shell for the time being. Here are the current updates to your code-behind file: public partial class MainWindow : System.Windows.Window { public MainWindow() { InitializeComponent(); } protected void FileExit_Click(object sender, RoutedEventArgs args) { // Terminate the application. Application.Current.Shutdown(); } protected void ToolsSpellingHints_Click(object sender, RoutedEventArgs args) { } protected void MouseEnterExitArea(object sender, RoutedEventArgs args) { } protected void MouseEnterToolsHintsArea(object sender, RoutedEventArgs args) { } protected void MouseLeaveArea(object sender, RoutedEventArgs args) { } } CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1095 8849CH29.qxd 10/16/07 12:17 PM Page 1095 www.free-ebooks-download.org Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Building the ToolBar Type Toolbars (represented by the ToolBar type in WPF) typically provide an alternative manner to acti- vate a menu option. Add the following markup directly after the closing scope of your <Menu> definition: <! Put Toolbar under the Menu > <ToolBar DockPanel.Dock ="Top" > <Button Content ="Exit" MouseEnter ="MouseEnterExitArea" MouseLeave ="MouseLeaveArea" Click ="FileExit_Click"/> <Separator/> <Button Content ="Check" MouseEnter ="MouseEnterToolsHintsArea" MouseLeave ="MouseLeaveArea" Click ="ToolsSpellingHints_Click" Cursor="Help" /> </ToolBar> Our <ToolBar> type consists of two Button types, which just so happen to handle the same events and are handled by the same methods in our code file. Using this technique, we are able to double-up our handlers to serve both menu items and toolbar buttons. Although this toolbar is making use of the typical push buttons, do know that the ToolBar type “is-a” ContentControl, and therefore you are free to embed any types into its surface (drop-down lists, images, graphics, etc.). The only other point of interest is that the Check button supports a custom mouse cursor via the Cursor property. ■Note The ToolBar type may optionally be wrapped within a <ToolBarTray> element, which controls layout, docking, and drag-and-drop operations for a set of ToolBar objects. Consult the .NET Framework 3.5 SDK docu- mentation for details. Building the StatusBar Type The StatusBar type will be docked to the lower portion of the <DockPanel> and contain a single <TextBlock> type, which up until this point in the chapter we have not made use of. Like a TextBox, a TextBlock can be used to hold text. In addition, TextBlock types honor the use of numerous tex- tual annotations such as bold text, underlined text, line breaks, and so forth. While our StatusBar does not technically need this support, another benefit of a TextBlock type is that it is optimized for small blurbs of text, such as UI prompts in a status bar pane. Add the following markup directly after the previous ToolBar definition: <! Put a StatusBar at the bottom > <StatusBar DockPanel.Dock ="Bottom" Background="Beige" > <StatusBarItem> <TextBlock Name="statBarText">Ready</TextBlock> </StatusBarItem> </StatusBar> At this point, your Visual Studio designer should look something like Figure 29-27. CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1096 8849CH29.qxd 10/16/07 12:17 PM Page 1096 www.free-ebooks-download.org Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 29-27. The current user interface of our spell-checker application Finalizing the UI Design The final aspect of our UI design is to define a splittable Grid type that defines two columns. On the left will be the Expander type that will display a list of spelling suggestions, wrapped within a <StackPanel>. On the right will be a TextBox type that supports multiple lines and has enabled spell checking. The entire <Grid> will be mounted to the left of the parent <DockPanel>. Add the following XAML markup to complete the definition of our Window’s UI: <Grid DockPanel.Dock ="Left" Background ="AliceBlue"> <! Define the rows and columns > <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <GridSplitter Grid.Column ="0" Width ="5" Background ="Gray" /> <StackPanel Grid.Column="0" VerticalAlignment ="Stretch" > <Label Name="lblSpellingInstructions" FontSize="14" Margin="10,10,0,0"> Spelling Hints </Label> CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1097 8849CH29.qxd 10/16/07 12:17 PM Page 1097 www.free-ebooks-download.org Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com <Expander Name="expanderSpelling" Header ="Try these!" Margin="10,10,10,10"> <! This will be filled programmatically > <Label Name ="lblSpellingHints" FontSize ="12"/> </Expander> </StackPanel> <! This will be the area to type within > <TextBox Grid.Column ="1" SpellCheck.IsEnabled ="True" AcceptsReturn ="True" Name ="txtData" FontSize ="14" BorderBrush ="Blue"> </TextBox> </Grid> Finalizing the Implementation At this point, your UI is complete. The only remaining tasks are to provide an implementation for the remaining event handlers. Here is the relevant code in question, which requires little comment by this point in the chapter: public partial class MainWindow : System.Windows.Window { protected void ToolsSpellingHints_Click(object sender, RoutedEventArgs args) { string spellingHints = string.Empty; // Try to get a spelling error at the current caret location. SpellingError error = txtData.GetSpellingError(txtData.CaretIndex); if (error != null) { // Build a string of spelling suggestions. foreach (string s in error.Suggestions) { spellingHints += string.Format("{0}\n", s); } // Show suggestions on Label within Expander. lblSpellingHints.Content = spellingHints; // Expand the expander. expanderSpelling.IsExpanded = true; } } protected void MouseEnterExitArea(object sender, RoutedEventArgs args) { statBarText.Text = "Exit the Application"; } protected void MouseEnterToolsHintsArea(object sender, RoutedEventArgs args) { statBarText.Text = "Show Spelling Suggestions"; } protected void MouseLeaveArea(object sender, RoutedEventArgs args) { CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1098 8849CH29.qxd 10/16/07 12:17 PM Page 1098 www.free-ebooks-download.org Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com statBarText.Text = "Ready"; } } So there you have it! With just a few lines of procedural code (and a healthy dose of XAML), we have the beginnings of a functioning word processor. To add just a bit more pizzazz requires an understanding of control commands. Understanding WPF Control Commands The next major discussion of this chapter is to examine the topic of control commands. Windows Presentation Foundation provides support for what might be considered “control-agnostic events” via control commands. As you know, a typical .NET event is defined within a specific base class and can only be used by that class or a derivative thereof. Furthermore, normal .NET events are tightly coupled to the class in which they are defined. In contrast, WPF control commands are event-like entities that are independent from a specific control and in many cases can be successfully applied to numerous (and seemingly unrelated) con- trol types. By way of a few examples, WPF supports Copy, Paste, and Cut commands, which can be applied to a wide variety of UI elements (menu items, toolbar buttons, custom buttons) as well as keyboard shortcuts (Ctrl+C, Ctrl+V, etc.). While other UI toolkits (such as Windows Forms) provided standard events for such purposes, the end result was typically redundant and hard to maintain code. Under the WPF model, com- mands can be used as an alternative. The end result typically yields a smaller and more flexible code base. The Intrinsic Control Command Objects WPF ships with numerous built-in control commands, all of which can be configured with associ- ated keyboard shortcuts (or other input gestures). Programmatically speaking, a WPF control command is any object that supports a property (often called Command) that returns an object imple- menting the ICommand interface, shown here: public interface ICommand { // Occurs when changes occur that affect whether // or not the command should execute. event EventHandler CanExecuteChanged; // Defines the method that determines whether the command // can execute in its current state. bool CanExecute(object parameter); // Defines the method to be called when the command is invoked. void Execute(object parameter); } While you could provide your own implementation of this interface to account for a control command, the chances that you will need to are slim, given functionality provided by the five WPF command objects out of the box. These static classes define numerous properties that expose objects that implement ICommand, most commonly the RoutedUICommand type, which adds support for the WPF routed event model. Table 29-4 documents some core properties exposed by each of the intrinsic command objects (be sure to consult the .NET Framework 3.5 SDK documentation for complete details). CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1099 8849CH29.qxd 10/16/07 12:17 PM Page 1099 www.free-ebooks-download.org Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Table 29-4. The Intrinsic WPF Control Command Objects WPF Control Command Object Example Control Command Properties Meaning in Life ApplicationCommands Close, Copy, Cut, Delete, Find, Open, Defines properties that Paste, Save, SaveAll, Redo, Undo represent application- level commands ComponentsCommands MoveDown, MoveFocusBack, MoveLeft, Defines properties that MoveRight, ScrollToEnd, map to common ScrollToHome commands performed by UI elements MediaCommands BoostBase, ChannelUp, ChannelDown, Defines properties that FastForward, NextTrack, Play, allow various media- Rewind, Select, Stop centric controls to issue common commands NavigationCommands BrowseBack, BrowseForward, Defines numerous Favorites, LastPage, NextPage, properties that are used Zoom for the applications that utilize the WPF navigation model EditingCommands AlignCenter, CorrectSpellingError, Defines numerous DecreaseFontSize, EnterLineBreak, properties typically used EnterParagraphBreak, MoveDownByLine, when programming with MoveRightByWord objects exposed by the WPF document API Connecting Commands to the Command Property If you wish to connect any of these command properties to a UI element that supports the Command property (such as a Button or MenuItem), you have very little work to do. To see how to do so, update the current menu system to support a new topmost menu item named Edit and three subitems to account for copying, pasting, and cutting of textual data: <Menu DockPanel.Dock ="Top" HorizontalAlignment="Left" Background="White" BorderBrush ="Black"> <MenuItem Header="_File" Click ="FileExit_Click" > <Separator/> <MenuItem Header ="_Exit" MouseEnter ="MouseEnterExitArea" MouseLeave ="MouseLeaveArea" Click ="FileExit_Click"/> </MenuItem> <! New menu item with commands! > <MenuItem Header="_Edit"> <MenuItem Command ="ApplicationCommands.Copy"/> <MenuItem Command ="ApplicationCommands.Cut"/> <MenuItem Command ="ApplicationCommands.Paste"/> </MenuItem> <MenuItem Header="_Tools"> <MenuItem Header ="_Spelling Hints" MouseEnter ="MouseEnterToolsHintsArea" MouseLeave ="MouseLeaveArea" Click ="ToolsSpellingHints_Click"/> </MenuItem> </Menu> CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS1100 8849CH29.qxd 10/16/07 12:17 PM Page 1100 www.free-ebooks-download.org Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Notice that each subitem has a value assigned to the Command property. By doing so, the menu items automatically receive the correct name and shortcut key (for example, Ctrl+C for a cut operation) in the menu item UI and the application is now “copy, cut, and paste” aware with no procedural code. Thus, if you were to run the application and select some of your text, you will be able to use your new menu items out of the box, as shown in Figure 29-28. Figure 29-28. Command objects provide a good deal of canned functionality for free. Connection Commands to Arbitrary UI Elements If you wish to connect a command to a UI element that does not support the Command property, doing so requires you to drop down to procedural code. Doing so is certainly not complex, but it does involve a bit more logic than you see in XAML. For example, what if you wished to have the entire window respond to the F1 key, so that when the end user presses this key, he or she would activate an associated help system? Assume your code file for the main window defines a new method named SetF1CommandBinding(), which is called within the constructor after the call to InitializeComponent(). This new method will programmatically create a new CommandBinding object, which is configured to operate with the ApplicationCommands.Help option, which is automatically F1-aware: private void SetF1CommandBinding() { CommandBinding helpBinding = new CommandBinding(ApplicationCommands.Help); helpBinding.CanExecute += CanHelpExecute; helpBinding.Executed += HelpExecuted; CommandBindings.Add(helpBinding); } Most CommandBinding objects will want to handle the CanExecute event (which allows you to specify whether the command occurs or not based on the operation of your program) and the Executed event (which is where you can author the content that should occur once the command occurs). Add the following event handlers to your Window-derived type (take note of the format of each method as required by the associated delegates): private void CanHelpExecute(object sender, CanExecuteRoutedEventArgs e) { // Here, you can set CanExecute to false if you wish to prevent the // command from executing if you desire. CHAPTER 29 ■ PROGRAMMING WITH WPF CONTROLS 1101 8849CH29.qxd 10/16/07 12:17 PM Page 1101 www.free-ebooks-download.org Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... that changes in the target do not affect the source In our example, changing the Content property of the Label does not set the position of the ScrollBar’s thumb If you wish to keep changes between the source and the target in sync, you can set the Mode property to TwoWay Thus, changing the value of the Label’s content changes the value of the scrollbar’s thumb position Of course, the end user would... change the content of the Label, as the content is presented in a read-only manner (we could of course change the value programmatically) To illustrate the use of the TwoWay mode, assume we have replaced the Label displaying the current scrollbar value with the following TextBox (note the value of the Text property) In this case, when you type a new value into the text area, the thumb position (and font... appending the next subelement using the XPath qualifier of the {Binding} markup extension Last but not least, the final row of the contains a that contains two Buttons (and a descriptive Label) to complete the UI The only points of interest here would be that we are handling the Click event of the OK button and the use of the IsDefault and IsCancel properties These establish which button... 8849CH 29. qxd 10/16/07 12:17 PM Page 1105 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com CHAPTER 29 s PROGRAMMING WITH WPF CONTROLS do w nl oa d o rg Here, the DataContext property has been set on the directly Therefore, as we move the thumb, not only will we see the current value on the Label, but we will also find the font size of the Button grow and shrink... is the value of the current double Using this type, we simply cast the type into an integer and return the new number The ConvertBack() method will be called when the value is passed from the destination to the source (if you have enabled a two-way binding mode) Here, we simply return the value straightaway By doing so, we are able to type a floating-point value into the TextBox (such as 99 .9) and. .. engine, you must be aware of the distinction between the source and the destination of the binding operation As you might expect, the source of a data-binding operation is the data itself (a Boolean property, relational data, etc.), while the destination (or target) is the UI control property that will use the data content (a CheckBox, TextBox, and so on) s Note The target property of a data-binding... either case, if you were to run this application, you would be pleased to find this Label updating without the need to write any procedural C# code (see Figure 29- 30) Figure 29- 30 Binding the ScrollBar value to a Label The DataContext Property w w fr In the current example, you have seen two approaches to establish the source and destination of a data-binding operation, both of which resulted in the. .. path within the XML document to be the subelement of , each of the XPath bindings for the column types use this as a starting point The first is displaying the ID attribute of the element using an XPathspecific syntax for plucking our attribute values (@caID) The remaining columns simply further qualify the path within the XML document by appending the next subelement... based on the same value Figure 29- 31 shows one possible output ee -e bo o The Mode Property ks - Figure 29- 31 Binding the ScrollBar value to a Label and a Button w w w fr When establishing a data-binding operation, you are able to choose among various modes of operation by setting a value to the Mode property at the time you establish the Path value By default, the Mode property is set to the value... dialog boxes can inform the caller which button has been clicked via the DialogResult property However, unlike the DialogResult property found in Windows Forms, in the WPF model, this property operates on a nullable Boolean value, rather than a strongly typed enumeration Thus, if you wish to inform the caller the user wishes to employ the data in the dialog box for use within the program (typically indicated . without the need to write any procedural C# code (see Figure 29 -30 ). Figure 29 -30 . Binding the ScrollBar value to a Label The DataContext Property In the current example, you have seen two approaches. support for the WPF routed event model. Table 29- 4 documents some core properties exposed by each of the intrinsic command objects (be sure to consult the .NET Framework 3. 5 SDK documentation. layout, docking, and drag -and- drop operations for a set of ToolBar objects. Consult the .NET Framework 3. 5 SDK docu- mentation for details. Building the StatusBar Type The StatusBar type will be docked

Ngày đăng: 12/08/2014, 23:20

Từ khóa liên quan

Mục lục

  • Prelims

  • Chapter 1

  • Chapter 2

  • Chapter 3

  • Chapter 4

  • Chapter 5

  • Chapter 6

  • Chapter 7

  • Chapter 8

  • Chapter 9

  • Chapter 10

  • Chapter 11

  • Chapter 12

  • Chapter 13

  • Chapter 14

  • Chapter 15

  • Chapter 16

  • Chapter 17

  • Chapter 18

  • Chapter 19

Tài liệu cùng người dùng

Tài liệu liên quan