Windows and Display Elements


The Application instance manages the windows that a program uses, and allows the program to switch between the active windows, as required. The Application contains a reference to one or more Window instances. At any given instant, one of the windows is at the foreground of the display. A Window instance contains a reference to a single child display element. You could just display this one element if you wanted to (for example, the display could be a single string of text). However, you will frequently want to have multiple items in different areas of the display. In this case, the container will hold a number of child items, each of which will be a particular display element.

Figure 7-14 shows how everything fits together. The window being displayed has a child that is a StackPanel container holding three elements: a string of text, an image, and a filled rectangle. These are arranged on top of each other (in a stack) on the display.

image from book
Figure 7-14: Applications, Windows, and Display components.

This seems like a rather complex way to manage the display, because we have all these additional containers to create and manage in addition to the items we actually want to put on the display. However, it is actually very useful, in that the container components can automatically compute and manage the position of the elements that they are given charge of, according to the instructions that you give them.

You can also create multiple windows on the display, but these must occupy different areas of the display; there is no support for overlapping windows and no concept of foreground and background windows on the display.

Using StackPanel to Lay Out a Display

The StackPanel container automatically calculated the position of the components in the display in Figure 7-14.

 // Create a window object and set its size to the size of the display. Window win = new Window(); win.Height = SystemMetrics.ScreenHeight; win.Width = SystemMetrics.ScreenWidth; win.Visibility = Visibility.Visible; // create StackPanel and make it the child of the main window StackPanel panel = new StackPanel(Orientation.Vertical); win.Child = panel; // create a text message and add it to the StackPanel Font messageFont = Resources.GetFont(Resources.FontResources.small); Text text = new Text(messageFont, "Snowflake"); text.HorizontalAlignment = HorizontalAlignment.Center; panel.Children.Add(text); // create an image and add it to the StackPanel Bitmap snowflake = Resources.GetBitmap(Resources.BitmapResources.MFsnowflake); Image image = new Image(snowflake); image.HorizontalAlignment = HorizontalAlignment.Center; panel.Children.Add(image); // create a rectangle and add it to the StackPanel Rectangle rect = new Rectangle(); rect.Fill = new SolidColorBrush(Colors.Red); rect.Width = 40; rect.Height = 40; rect.HorizontalAlignment = HorizontalAlignment.Center; panel.Children.Add(rect); // Start the application with this window app.Run(win); 

The preceding code produced the display in Figure 7-14. The StackPanel is configured to stack the display elements vertically (they can also be arranged horizontally), and each element is also configured to align itself centrally in the display area allocated to it by the StackPanel.

It is possible to create even more complex arrangements by adding container objects in addition to components.

 // create StackPanel and make it the child of the main window StackPanel panel = new StackPanel(Orientation.Vertical); win.Child = panel; // create a top line StackPanel with the time in the top right corner StackPanel topLinePanel = new StackPanel(Orientation.Horizontal); // create a text message and add it to the top line Font messageFont = Resources.GetFont(Resources.FontResources.small); Text text = new Text(messageFont, "Snowflake"); text.Width = 100; text.TextAlignment = TextAlignment.Left; // add to the top line topLinePanel.Children.Add(text); // create a time value Text time = new Text(messageFont, "16:22"); time.TextAlignment = TextAlignment.Right; time.Width = win.Width - text.Width; // add to the top line topLinePanel.Children.Add(time); // add the top line to the display panel.Children.Add(topLinePanel); 

The preceding code creates a horizontal StackPanel that is positioned at the top of the display. The topLinePanel contains two text items, one is a message and the other could be the current time. The width of these items is set so that they fill the entire line, and the second text item is aligned at the right edge. This entire StackPanel is then added to the display to give a top-line display, as shown in Figure 7-15.

image from book
Figure 7-15: Split top line using StackPanel.

Note 

It is possible to create your own container objects with their own layout behaviors. We will be doing this later on, when we create a new text display.

Placing Components Precisely Using the Canvas

You can provide the StackPanel with hints as to the location of the items it is drawing on the display, but you do not have precise pixel-level control over where on the display elements are drawn. However, the Windows Presentation Framework provides an alternative panel type that can be used to place components precisely on the display. The Canvas class implements a panel that allows you to specify the exact position of items that are added to it.

 Application app = new Application(); // Create a window object and set its size to the size of the display. Window win = new Window(); win.Height = SystemMetrics.ScreenHeight; win.Width = SystemMetrics.ScreenWidth; win.Visibility = Visibility.Visible; Canvas myCanvas = new Canvas(); win.Child = myCanvas; myCanvas.Width = win.Width; myCanvas.Height = win.Height; // create a text message and place it in the top left Font messageFont = Resources.GetFont(Resources.FontResources.small); Text text = new Text(messageFont, "Snowflake"); text.Width = 100; text.TextAlignment = TextAlignment.Left; Canvas.SetTop(text, 0); Canvas.SetLeft(text, 0); myCanvas.Children.Add(text); // create a time value Text time = new Text(messageFont, "16:22"); time.TextAlignment = TextAlignment.Right; time.Width = SystemMetrics.ScreenWidth - text.Width; Canvas.SetTop(time, 0); Canvas.SetLeft(time, win.Width - time.Width); myCanvas.Children.Add(time); 

The preceding code shows an instance of the Canvas class being configured to place the text and the time display at opposite sides of the top of the display, to get the same appearance as we saw in Figure 7-15. Display elements are added to the myCanvas instance in exactly the same way as before, but their position on the display can be set precisely.

 Canvas.SetTop(text, 0); Canvas.SetLeft(text, 0); myCanvas.Children.Add(text); 

This code places the text component at the top left corner of the myCanvas instance. The top and left values are relative to the canvas itself, not the display.

Note 

The SetTop and SetLeft methods are static members that are part of the Canvas class, not the myCanvas instance. This arrangement is part of the way that the Windows Presentation Classes are designed and is not an issue as such, but it can be the source of problems if your code tries to call these methods on instances of the class, that is, myCanvas.SetTop(text,0) would cause a compilation error.

As with the StackPanel, it is possible to use a Canvas instance as a child element in another container. This allows you to create displays in which part of the display has elements positioned to pixel accuracy, and other elements are placed automatically.

Although the way in which the windows are constructed is slightly more complex than simple use of the Bitmap class, it can be very time-saving to have components automatically positioned on the display rather than having to perform the positioning by hand. This section has really only scratched the surface of the subject, and you are strongly advised to examine the examples in this section in detail for more information.

Updating Display Elements

We can now create our windows and lay out the elements that make up our display. The next thing to do is to allow updating of display elements. As an example, we might want to make a clock shown on our display actually update with the current date and time. To do this, we will need a timer to generate events that we can then use to update the display. We have seen these before, when we created the flashlight-finder feature in the section titled "Implementing a Flashlight-Finder Feature Using a Timer" in Chapter 4, "Building a Device."

 // start the clock System.Threading.Timer timer = new System.Threading.Timer(    new System.Threading.TimerCallback(tick),    null, // object to pass into the timer    500, // time in milliseconds before first tick    500); // interval between ticks 

This method call creates a timer that will call the method tick every half second. This method can then update the text item on our display. We can use the DateTime class to provide us with the date and time.

 static void tick(object stateInfo) {    time.TextContent = DateTime.Now.ToString();    time.Invalidate(); } 

The first line of the method sets the content of the appropriate Text element to the current date and time, in the form mm/dd/yyyy hh:mm:ss. The second line is very important. It invalidates the time element, requesting that it be updated on the display. If we do not call this method, the display will not change. Every display element supports the Invalidate method. You could get the same update effect by invalidating the StackPanel containing the Text element. However, when you invalidate a container element, this requests a redraw of every element in it, which results in a lot of unnecessary work for the graphics system. When invalidating elements, you can reduce the amount of redraw effort to a minimum by just invalidating the changed ones.

Note 

There are significant differences between the Windows Presentation Foundation implementation in the .NET Micro Framework and that implementation based on full .NET 3.0. The invalidate behavior is managed differently, with no Invalidate method in the full framework.

You can use a number of other forms of Invalidate to inform the display system that, for example, the size of a component has changed (InvalidateMeasure) or the layout of the items in a component has changed (InvalidateLayout). You will need to use these methods if any of these aspects of your display items change.




Embedded Programming with the Microsoft .Net Micro Framework
Embedded Programming with the Microsoft .NET Micro Framework
ISBN: 0735623651
EAN: 2147483647
Year: 2007
Pages: 118

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net