Programming UI Elements

XAML provides a number of visual elements for creating your user interfaces. These are listed in detail in Chapter 2, where their properties are discussed. The set of UI elements includes Canvas, Ellipse, Glyphs, Image, Line, MediaElement, Path, Polygon, Polyline, Rectangle, Run, Shape, and TextBlock.

Each of these elements supports a rich set of methods and events, and these will be listed and discussed in the next several sections.

UI Element Methods

UI elements provide functions that can be called from JavaScript to allow you to manipulate them to create rich application interaction. These methods are common to all of the UI elements.

The AddEventListener and RemoveEventListener Methods

The AddEventListener method is used to add an event listener at run time to the UI element. This is useful for separating design and development—the developer doesn’t add anything directly to the XAML that the designer produces. Instead, the developer adds event handling code to a JavaScript file (or block). UI element events you might handle are discussed later in this chapter.

Note

When using the AddEventListener method, be sure to define the name of the event using a lowercase letter for the first character. For example, if you are defining an event handler for the MouseLeftButtonDown event using the addEventListener method, you declare it using the string “mouseLeftButtonDown”.

Following is an example that shows you how to add an event listener at run time. This example adds an event handler that traps the mouse click and specifies that the event should be handled by a JavaScript function called handleMouse. This function, like most event handlers, takes two parameters, a sender and event arguments. Because it is a mouse event, it takes an instance of MouseEventArgs, which allows us to get the x- and y-coordinates of the mouse at the time of the event:

<script type="text/javascript"> 
   function handleLoad(control, userContext, sender)
   {
       sender.addEventListener("mouseLeftButtonDown",handleMouse); 
   } 
   function handleMouse(sender, mouseEventArgs) 
   { 
       alert(mouseEventArgs.getPosition(null).x + ":" 
           + mouseEventArgs.getPosition(null).y); 
   } 
</script>

You can destroy the connection at run time using the RemoveEventListener method with the same syntax.

The findName Method

This method is used to search through the child elements of a particular element to find a named object. It will return a reference to the specified object if it exists; otherwise it will return null. For example, take a look at this XAML code:

<Canvas xmlns=https://schemas.microsoft.com/client/2007
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
        Height="400" Width="400"> 
  <TextBlock Canvas.Top="0" x:Name="txt1" Text="TextBlock1" />
  <TextBlock Canvas.Top="20" x:Name="txt2" Text="TextBlock2" />
  <TextBlock Canvas.Top="40" x:Name="txt3" Text="TextBlock3" /> 
</Canvas>

This code defines three text blocks called txt1, txt2, and txt3 using the x:Name property. You can now use the findName method to find a named node, obtain a reference to it, and then edit it using that reference. In this case, it is done within the handleLoad event handler.

<script type="text/javascript"> 
    function handleLoad(control, userContext, sender)
    { 
         var t1 = sender.findName("txt1"); 
         t1.Text = "TextBlock1 has changed"; 
    } 
</script>

Accessing the Control with the GetHost Method

UI elements provide a GetHost method that can be used to get a handle to the containing Sil-verlight control. This is useful when you want to use an event handler on one control to access a different control.

An example of this can be seen in the event handler for the download progress of a Downloader object. In this case, the function doesn’t have direct access to the Silverlight control, but in order to manipulate the properties of another element, the UI element event handler needs a reference to that element (in this example, a reference to the Silverlight control). The UI element event handler can do this by getting a reference to the control using getHost, and then from that reference it can find the other element.

function handleDLProgress(sender, args) 
{ 
    var ctrl = sender.getHost(); 
    var t1 = ctrl.content.findName("txt1"); 
    var v = sender.downloadProgress * 100; 
    t1.Text = v + "%"; 
}

Accessing a Parent Element with the getParent Method

You may have cases in which you want to access a UI element’s parent. It is inefficient to get a reference to the Silverlight control and then to use findName to get the parent, so the getParent method is available. It will return a reference to the parent upon success; otherwise it will return null.

Using the GetValue and SetValue Methods

You can always access properties with the traditional dot syntax, object.propertyname, but an alternative methodology, using the GetValue method, exists to support attached properties. So, for example, if you want to access the Canvas.Top property, you cannot do it with object.Canvas.Top. You must use the object.GetValue("Canvas.Top") syntax. GetValue can also be used to access nonattached properties, even though in that case the dot notation is equivalent.

In a similar way, you can use the SetValue method to set a property value for either a simple or attached property. This method takes two parameters. The first is the name of the property, and the second is the value to assign. Following is an example:

var t1 = ctrl.content.findName("txt1");
t1.setValue("Canvas.Top",20);

Using SetFontSource

The TextBlock element supports an additional method, SetFontSource, that adds font files to the object’s collection of fonts that it can use. So, if you want to use a new font to render the text—for example, if you need to support a foreign character set (such as a font used for an East Asian language), then you can download the font with a Downloader object and use the Set-FontSource method, passing it the Downloader and the TextBlock will use that font. To use this method, you must have the rights to distribute the font (or a subset thereof).

Following is an example using the SetFontSource method. In this case, I have an XAML document that was defined using Expression Blend and that uses some Chinese text:

<Canvas 
  xmlns=https://schemas.microsoft.com/client/2007
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
  Width="640" Height="480" Background="White"> 
   <TextBlock x:Name="myTextBlock" Width="152" Height="64" 
     Canvas.Left="184" Canvas.Top="56" Text=" 好,  好 ?" 
     TextWrapping="Wrap" MouseLeftButtonDown="handleIt" /> 
</Canvas>

When this is rendered, the default Silverlight font set will not recognize the Chinese characters and will print them as unprintable character blocks (typically small squares). However, you can use a Downloader object to download a font that does support Chinese text. The previous XAML code defines a MouseLeftButtonDown event handler function called handleIt. You can see that function here:

// Event handler for initializing and executing a font file download request.
function handleIt(sender, eventArgs) 
{ 
   // Retrieve a reference to the control. 
   var control = sender.getHost(); 
   // Create a Downloader object. 
   var downloader = control.createObject("downloader"); 
   // Add Completed event. 
   downloader.addEventListener("Completed", "onCompleted"); 
   // Initialize the Downloader request. 
   downloader.open("GET", "SIMHEI.TTF", true); 
   // Execute the Downloader request. 
   downloader.send(); 
}

This creates a download object that downloads the font and defines an event handler onCom-pleted that will handle the Completed event that fires when the download is complete. This event will then set the font source for the TextBlock to the supporting font, and then Silverlight will render the Chinese characters using the new font source.

// Event handler for the Completed event.
function onCompleted(sender, eventArgs) 
{ 
   // Retrieve the TextBlock object. 
   var myTextBlock = sender.findName("myTextBlock"); 
   // Add the font files in the downloaded object 
   // to the TextBlock's type face collection.
   myTextBlock.setFontSource(sender); 
   // Set the FontFamily property to the friendly name of the font.
   myTextBlock.fontFamily = "Simhei"; 
}

UI Element Events

UI elements support a number of events that may be wired to JavaScript functions either by using the AddEventListener methodology to add them at run time, or by using the appropriate XAML attribute to add them at design time. For example, if you want to wire a control’s MouseLeftButtonDown event using JavaScript, you do it with the AddEventListener method:

t1.addEventListener("MouseLeftButtonDown", handleMouseDown);

To wire the event in XAML, you can use the attribute that has the same name as the desired event (such as "MouseLeftButtonDown"). Following is an example:

<TextBlock Canvas.Top="0" x:Name="txt1" Text="Status"
MouseLeftButtonDown="handleMouseDown"/>

The events that are supported on the UI element are as follows:

  • GotFocus This is fired when the element receives mouse focus.
  • KeyDown Occurs on an element when it has focus and a key is pressed. The event handler takes two attributes. The first of these is the sender, representing a reference to the object that raised the event. The second is a KeyEventArgs object. This has a number of properties of its own. The first is key, which is an integer value that represents the key that was pressed. It is not operating-system specific, and specific details about how this maps to actual keys can be found in the Silverlight SDK. Another property is the platformKeyCode, which is operating-system specific. In addition to the actual key, the Boolean properties shift and ctrl are exposed. These indicate whether or not the Shift and Ctrl keys are pressed.
  • KeyUp This occurs on an element when it has focus and the key is released. It provides for the same two attributes as the KeyDown event.
  • Loaded This fires when the Silverlight content is loaded into the host Silverlight control and parsed, but before it is rendered.
  • LostFocus This is the opposite of the GotFocus event; it fires when the object loses focus.
  • MouseEnter This fires when the mouse enters the bounding area of the object.
  • MouseLeave This is the opposite of MouseEnter event; it fires when the mouse leaves the area of the bounding object.
  • MouseLeftButtonDown This occurs when the user presses the left mouse button over the UI element.
  • MouseLeftButtonUp This occurs when the left mouse button is released. MouseMove This occurs when the cursor moves over the UI element.

Implementing Drag and Drop

You can use the mouse event handlers and Silverlight’s CaptureMouse and ReleaseMouseCapture methods to implement drag and drop in Silverlight.

First of all, let’s take a look at a XAML document containing several shapes that may be dragged and dropped around the canvas. These shapes wire their mouse event handlers (MouseLeftButtonDown, MouseLeftButtonUp and MouseMove) to the onMouseDown, onMouseUp, and onMouseMove functions respectively.

<Canvas xmlns=https://schemas.microsoft.com/client/2007
        xmlns:x=https://schemas.microsoft.com/winfx/2006/xaml 
        Height="400" Width="400"> 
<Ellipse Canvas.Top="0" Height="10" Width="10" Fill="Black" 
         MouseLeftButtonDown="onMouseDown" 
         MouseLeftButtonUp="onMouseUp" 
         MouseMove="onMouseMove" /> 
<Ellipse Canvas.Top="20" Height="10" Width="10" Fill="Black" 
         MouseLeftButtonDown="onMouseDown" 
         MouseLeftButtonUp="onMouseUp" 
         MouseMove="onMouseMove"/> 
<Ellipse Canvas.Top="40" Height="10" Width="10" Fill="Black" 
         MouseLeftButtonDown="onMouseDown" 
         MouseLeftButtonUp="onMouseUp" 
         MouseMove="onMouseMove"/> 
<Ellipse Canvas.Top="60" Height="10" Width="10" Fill="Black" 
         MouseLeftButtonDown="onMouseDown" 
         MouseLeftButtonUp="onMouseUp" 
         MouseMove="onMouseMove"/> 
</Canvas>

Now let’s take a look at each of the event handler functions. First, let’s examine the mouse down event handler. When dragging, you want that control to “own” the mouse events, so you use the captureMouse method. You’ll also want to remember the starting points for the dragging, so these will be recorded by the event handler. Finally, you’ll flag that the mouse is down using a Boolean variable isMouseDown.

var beginX; 
var beginY; 
var isMouseDown = false; 
function onMouseDown(sender, mouseEventArgs) 
{ 
    beginX = mouseEventArgs.getPosition(null).x; 
    beginY = mouseEventArgs.getPosition(null).y; 
    isMouseDown = true; 
    sender.captureMouse(); 
}

Now, in a drag-and-drop operation, you want to move the item with the mouse. So, when the MouseMove event fires, you will record the current mouse coordinates and use them to figure out where the item should be moved as well.

The mouseEventArgs allow us to retrieve the current x- and y-coordinates of the mouse, and since the Ellipse object that is being dragged in the example is the sender, you can set its left and top properties by adding the delta on the x- and y-coordinates to their respective initial values.

Also note that onMouseMove will fire whether you are dragging or not, so we use the isMouse-Down to check if we are currently dragging. (Remember, it was set in the previous MouseDown event handler.)

function onMouseMove(sender, mouseEventArgs) 
{ 
  if (isMouseDown == true) 
    { 
        var currX = mouseEventArgs.getPosition(null).x; 
        var currY = mouseEventArgs.getPosition(null).y; 
        sender["Canvas.Left"] += currX - beginX; 
        sender["Canvas.Top"] += currY - 
        beginY; beginX = currX; 
        beginY = currY; 
    } 
}

Finally, when the mouse button is released, you will release the mouse capture and reset isMouseDown. The ellipses will stay in their new positions.

function onMouseUp(sender, mouseEventArgs) 
{ 
    isMouseDown = false; 
    sender.releaseMouseCapture(); 
}

Figure 5-4 shows the four ellipses with drag and drop enabled, and Figure 5-5 shows the position of the ellipses after the drag-and-drop operation has been completed.

Cc500385.Figure_C05625396_4(en-us,MSDN.10).png

Figure 5-4 Four ellipses with drag and drop enabled.

Cc500385.Figure_C05625396_5(en-us,MSDN.10).png

Figure 5-5 Dragging and dropping the ellipses.

< Back      Next >