Silverlight Mouse Support

Silverlight Mouse Support

Silverlight provides a set of events that allow you to respond to mouse actions, such as moving or clicking the mouse.

This topic contains the following sections:

  • Mouse Events
  • Defining a Mouse Event Handler
  • Event Bubbling
  • Implementing Drag-and-Drop Functionality
  • Notes

 

For a listing of all supported events, see Silverlight Events. For information on keyboard events, see Silverlight Keyboard Support.

Mouse Events

Silverlight provides the following set of mouse events.

Event Description
MouseMove Occurs when the coordinate position of the mouse pointer changes. The mouseEventArgs parameter contains input information.
MouseEnter Occurs when the mouse enters the bounding area of an object. The mouseEventArgs parameter contains input information.
MouseLeave Occurs when the mouse leaves the bounding area of an object.  The mouseEventArgs parameter is null.
MouseLeftButtonDown Occurs when the left mouse button is down. The mouseEventArgs parameter contains input information.
MouseLeftButtonUp Occurs when the left mouse button is up, following a MouseLeftButtonDown event. The mouseEventArgs parameter contains input information.

Mouse Event Parameters

A Silverlight event-handler function contains two parameters, described in the following table.

Parameter Description
sender Identifies the Silverlight object that generated the event. You can retrieve the type value of the object by calling the ToString method on the parameter value.
mouseEventArgs Identifies the the current x-coordinate and y-coordinate positions of the mouse pointer, as well as whether the SHIFT and CTRL keys are down. The MouseLeave event, however, does not define this parameter; in this case, the value of mouseEventArgs is null.

Note   If the Silverlight event-handler function does not reference the sender and mouseEventArgs parameters, you do not have to define them as part of the function declaration.

Defining a Mouse Event Handler

You can define mouse event-handler functions for Silverlight objects. The following XAML example shows how to define the MouseEnter and MouseLeave events for two Ellipse objects. Notice that the objects share the event-handler functions for each event.

XAML
<Canvas
  xmlns="https://schemas.microsoft.com/client/2007"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  MouseMove="onMouseMove">
  <Ellipse
    MouseEnter="onMouseEnter"
    MouseLeave="onMouseLeave"
    Height="100" Width="100"
    Fill="Teal" />
  <Ellipse
    MouseEnter="onMouseEnter"
    MouseLeave="onMouseLeave"
    Canvas.Left="120"
    Height="100" Width="100"
    Fill="Teal" />
  <TextBlock x:Name="Status" Canvas.Top="120" />
</Canvas>

The following JavaScript example shows the corresponding Silverlight event-handler functions for the MouseEnter and MouseLeave events.

JavaScript
function onMouseEnter(sender, mouseEventArgs)
{
    sender.fill = "Coral";
}
function onMouseLeave(sender, eventArgs)
{
    sender.fill = "Teal";
}

The following illustration shows the result of the first ellipse receiving the MouseEnter event.

Ellipses change color during MouseEnter and MouseLeave events

Ellipses change color during MouseEnter and MouseLeave events

Using Mouse Events that Pass a MouseEventArgs Parameter

The MouseMove, MouseEnter, MouseLeftButtonDown, and MouseLeftButtonUp events set the mouseEventArgs parameter so that input information can be retrieved. The following JavaScript example shows how to use the GetPosition method to retrieve the current mouse pointer position for the object that received the MouseMove event. In this case, the element parameter is set to null, which means that the returned Point value represents the mouse pointer position of the object relative to the upper-left corner of the plug-in area.

JavaScript
function onMouseEnter(sender, mouseEventArgs)
{
    sender.fill = "Coral";
}
function onMouseLeave(sender, eventArgs)
{
    sender.fill = "Teal";
}

The element parameter of the GetPosition method can also be set to any UIElement-derived object that is contained by the Silverlight plug-in. The returned mouse pointer position is relative to element. Depending on the location of element relative to the object, the coordinate values of the mouse position may be negative values.

The following illustration shows how the green Rectangle object uses the red Rectangle object as the value of element, in order to return mouse position values that are relative to the coordinate space of element. This means that clicking near the upper-left corner of the green Rectangle generates mouse position values that are negative with respect to the red Rectangle.

Returning relative mouse position values

Returning relative mouse position values

Note   Silverlight version 1.0 does not support high DPI; therefore, objects rendered on the screen and the coordinate system do not scale in response to monitor resolution. In addition, coordinates used by mouse events are not affected by monitor resolution.

The following JavaScript example shows how to retrieve the current mouse pointer position for the object relative to element.

JavaScript
function onMouseLeftButtonUp(sender, mouseEventArgs)
{
    // Return a Point object representing the x- and y-coordinates of the current mouse position
    // relative to the reference object.
    var pt = mouseEventArgs.getPosition(sender.findName("referenceObject"));
    // Display the current mouse position.
    sender.findName("Status").text = pt.x + " : " + pt.y;
}

Defining Mouse Events in JavaScript

To add and remove event-handler functions in JavaScript, use the AddEventListener and RemoveEventListener methods. The following JavaScript example shows how to add events to a TextBlock object.

JavaScript
function onLoaded(sender, eventArgs)
{
    textBlock = sender.findName("Status");
    var entertoken1 = textBlock.addEventListener("MouseEnter", onMouseEnter);
    var leavetoken1 = textBlock.addEventListener("MouseLeave", onMouseLeave);
}

To remove an existing event-handler function, use the RemoveEventListener method. The following JavaScript example shows how to remove events from a TextBlock object.

JavaScript
function removeEvents()
{
    textBlock.removeEventListener("MouseEnter", entertoken1);
    textBlock.removeEventListener("MouseLeave", leavetoken1);
}

Event Bubbling

Silverlight supports the concept of a bubbled event for input events such as mouse events. A bubbled event is an event that is passed from a child object and is forwarded up to each of its ancestors in the object hierarchy.

The MouseMove event is a bubbled event. This means that if multiple MouseMove events are defined for an object and its ancestors, the event is received by each object in the ancestor hierarchy, starting with the object that directly receives the event. Consider the following XAML example in which MouseMove events are defined for a Canvas and two Rectangle objects. In this case, if you move the mouse over either Rectangle object, it receives the MouseMove event. The event is then bubbled up to the parent Canvas.

XAML
<!-- Rectangle MouseMove event fires first, then Canvas MouseMove event -->
<Canvas
  xmlns="https://schemas.microsoft.com/client/2007"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  Width="640" Height="480"
  Background="OldLace"
  MouseMove="onCanvasMouseMove"
  Loaded="onLoaded">
  <Rectangle
    x:Name="RectA"
    MouseMove="onRectMouseMove"
    Width="100" Height="100" Fill="PowderBlue" />
  <Rectangle
    x:Name="RectB"
    MouseMove="onRectMouseMove"
    Width="100" Height="100" Fill="Gold"
    Canvas.Top="50" Canvas.Left="50" Opacity="0.5" />
  <TextBlock x:Name="statusTextBlock" Canvas.Top="180" />
</Canvas>

The following JavaScript example shows how to implement the MouseMove event-handler functions for the corresponding XAML content in the previous example.

JavaScript
var statusTextBlock;
function onLoaded(sender) {
  statusTextBlock = sender.findName("statusTextBlock");
}
function onCanvasMouseMove(sender, mouseEventArgs)
{
  var msg = "x:y = " + mouseEventArgs.getPosition(null).x + ", " + mouseEventArgs.getPosition(null).y;
  // Uncomment the next line to show MouseMove event bubbling.
  //statusTextBlock.text = "Canvas: " + msg;
}
function onRectMouseMove(sender, mouseEventArgs)
{
  var msg = " x:y = " + mouseEventArgs.getPosition(null).x + ", " + mouseEventArgs.getPosition(null).y;
  statusTextBlock.text = sender.name + msg;
}

Depending on your event handling strategy, you might want only one event handler to react to a bubbling event. For instance, if you have a specific MouseLeftButtonDown handler for a Canvas or Rectangle that functions as a button, and a general MouseLeftButtonDown handler on the root Canvas, you might not want the root-level Canvas handler handling the button click. The event bubbles upwards in the hierarchy, so the button has the first chance to handle the event. You can establish a variable that is used as a flag, at a scope that both handlers can access. When the button handler executes, it sets this flag. Then, the root-level handler should check that flag and only execute if the flag was not set.

Implementing Drag-and-Drop Functionality

Drag-and-drop functionality is a very useful feature of interactive content. You can easily add drag-and-drop functionality to a Silverlight plug-in by implementing simple event-handler functions on three mouse events: MouseLeftButtonDown, MouseLeftButtonUp, and MouseMove.

A drag-and-drop operation is a sequence of three steps:

  • Mouse down. The object is selected. The object must have exclusive access to all mouse events generated by the Silverlight plug-in that contains it.
  • Mouse move. The object moves to a new position, relative to the current position of the mouse.
  • Mouse up. The object stops responding to mouse events.

Note   The drag-and-drop behavior described in this topic is limited to a single Silverlight plug-in. You cannot drag an object between two Silverlight plug-ins.

The following XAML example shows two objects that share the same three mouse event handlers, because the drag-and-drop functionality is implemented in the same way for all the objects.

XAML
<!-- Define a circular object. -->
<Canvas
  MouseLeftButtonDown="onMouseDown"
  MouseLeftButtonUp="onMouseUp"
  MouseMove="onMouseMove"
  Canvas.Top="20" Canvas.Left="50">
  <Ellipse
    Height="100" Width="100"
    Fill="Gold"
    Stroke="Black" StrokeThickness="4" />
  <Ellipse
    Height="50" Width="50"
    Canvas.Top="25" Canvas.Left="25"
    Fill="Black" />
</Canvas>
<!-- Define a diamond-shaped object. -->
<Canvas
  MouseLeftButtonDown="onMouseDown"
  MouseLeftButtonUp="onMouseUp"
  MouseMove="onMouseMove"
  Canvas.Top="140" Canvas.Left="100">
  <Canvas.RenderTransform>
    <RotateTransform Angle="45" />
  </Canvas.RenderTransform>
  <Rectangle
    Height="100" Width="100"
    Fill="Coral"
    Stroke="Black" StrokeThickness="4" />
</Canvas>

Note   The Canvas object is used to group all the elements that compose an object. This enables the whole group to act as a unit during drag-and-drop operations. Likewise, any RenderTransform applied to the Canvas object affects all the elements of the object.

Starting the Drag-and-Drop Operation

The onMouseDown event-handler function in the following JavaScript example initiates the drag-and-drop operation by storing the beginning position of the mouse, setting a flag to indicate that the drag-and-drop operation is in effect, and gaining exclusive access to mouse events by invoking the CaptureMouse method. When an object has captured the mouse, it receives mouse input regardless of whether the cursor is within its borders.

JavaScript
// Define state variables for drag-and-drop operation.
var beginX;
var beginY;
var isMouseDown = false;
// Start drag-and-drop operation.
function onMouseDown(sender, mouseEventArgs)
{
    // Set the beginning position of the mouse.
    beginX = mouseEventArgs.getPosition(null).x;
    beginY = mouseEventArgs.getPosition(null).y;
    isMouseDown = true;
    // Ensure that this object is the only one receiving mouse events.
    sender.captureMouse();
}

Moving an Object During the Drag-and-Drop Operation

The onMouseMove event-handler function in the following JavaScript example determines whether the drag-and-drop operation is in effect by testing the value of the isMouseDown variable. If the drag-and-drop operation is in effect, the incremental difference between the last stored mouse position and the current mouse position is applied to the object's Canvas.Top and Canvas.Left values.

JavaScript
// Reposition object during drag-and-drop operation.
function onMouseMove(sender, mouseEventArgs)
{
    // Determine whether the mouse button is down.
    // If so, move the object.
    if (isMouseDown == true)
    {
        // Retrieve the current position of the mouse.
        var currX = mouseEventArgs.getPosition(null).x;
        var currY = mouseEventArgs.getPosition(null).y;
        // Reset the location of the object.
        sender["Canvas.Left"] += currX - beginX;
        sender["Canvas.Top"] += currY - beginY;
        // Update the beginning position of the mouse.
        beginX = currX;
        beginY = currY;
    }
}

Stopping the Drag-and-Drop Operation

The onMouseUp event-handler function in the following JavaScript example stops the drag-and-drop operation by setting a flag to indicate that the drag-and-drop operation is no longer in effect, and invoking the ReleaseMouseCapture method on the object. This method releases the object's exclusive access to the Silverlight plug-in's mouse events. This means that all objects can now receive mouse events.

JavaScript
// Stop drag-and-drop operation.
function onMouseUp(sender, mouseEventArgs)
{
    isMouseDown = false;
    // Allow all objects to receive mouse events.
    sender.releaseMouseCapture();
}

How Mouse Capture Enables Drag-and-Drop Functionality

The reason why all the objects in the preceding XAML example can share mouse event handlers is that each object enables mouse capture during the drag-and-drop operation. As a result, when you drag an object such as the circular object, no mouse events are sent to other objects. Therefore, when the circular object is dragged under the diamond-shaped object, the diamond-shaped object does not receive mouse events, although the mouse cursor is directly over it.

Dragging the circular object does not trigger mouse events for the diamond-shaped object

Dragging the circular object does not trigger mouse events for the diamond-shaped object

Mouse capture also ensures that drag-and-drop operations perform correctly when you move the mouse quickly. As long as mouse capture is enabled, the mouse cursor does not need to be exactly on the object being dragged. Eventually, the object that is being dragged will render under the mouse cursor. For more information on Drag and Drop, see How to: Drag and Drop Objects.

Notes

In Apple Safari, if an unhandled exception occurs in the event-handler code, no further mouse-related event handlers are called for the lifetime of the Silverlight plug-in. In other browsers, only the handler that contained the error will exit (usually with a scripting error returned to the browser); other errorless mouse event handlers can continue to function.

See Also

Silverlight Events
Silverlight Keyboard Support
Silverlight Object Models and Scripting to the Silverlight Plug-in
Silverlight Error Handling
How to: Drag and Drop Objects
Overviews and How-to Topics