Hace un par de semanas, formaba parte de un pequeño equipo de desarrollo de una aplicación en Silverlight 2, y casi llegando al final del desarrollo pensamos que el uso de un menú contextual podría sernos de gran utilidad. Nos encontramos con dos problemas.
Primero , no existe un control para tal funcionalidad en el conjunto de controles de Silverlight 2 (por ahora) - no pasa nada pensamos, nos creamos uno. Aquí nos apareció el segundo problema: El plugin de Silverlight no implementa los eventos sobre el botón derecho (si pulsamos el botón derecho sobre una aplicación Silverlight nos aparece un menú contextual propio del plugin). Por motivos de tiempo desistimos de crear un menú contextual.
Suerte que un servidor todavía disfruta de un poco de tiempo libre los fines de semana
.
El código de este ejemplo lo puedes descargar aquí.
Eventos sobre el botón derecho del ratón:
Parece ser que los motivos por los que el equipo de desarrollo de Silverlight no implementó los eventos sobre el botón derecho del ratón, es el requerimiento de que las aplicaciones Silverlight sean totalmente funcionales en los navegadores Internet Explorer, Firefox y Safari. He aquí el problema, en MAC no hay botón derecho.
Dicho esto, podríamos pensar que no es posible capturar el evento onClick sobre el botón derecho del ratón, pero esto no es verdad. Para ello tendríamos que seguir los siguientes pasos:
-
Añadir el atributo oncontextmenu a la etiqueta <body> de la pagina, el cual controla la pulsación del botón derecho en la pagina, con el valor “return false;”. Con esto evitamos que nos aparezca menú propio del plugin.
-
Añadir el atributo oncontextmenu sobre el div que contendrá la aplicación Silverlight, con el valor de una función javascript, la cual pasará a controlar la acción de crear un contextmenu.
-
Desde la función Javascript mencionada anteriormente llamaremos a un método publico de la aplicación silverlight que tendrá la lógica de crear nuestro menú.
Para crear un método publico accesible desde javascript:
a. Declarar la clase de que definine la pagina como [ScriptableType]
b. Definir el método público como [ScriptableMember]
Con esto ya debería de funcionar, pero no, hay un pequeño matiz. Para poder gestionar el evento oncontextmenu, tenemos que crear nuestra aplicación Silverlight de la misma forma que se hacía con la versión alfa 1.1, es decir, tendremos que añadir a nuestro proyecto la librería de javascript Silverligth.js y el fichero asociado pagina.js que si recordamos es el encargado de crear el objeto Silveright. Tranquilos, en el SDK se proporciona la versión 2 de la librería silverlight.js, por lo que el resultado es el mismo. Los motivos por los que hay que generar de esta manera el objeto Silverlight los desconozco.
Nuestra Solución:
OK, ahora sabemos que se puede controlar el evento onClick sobre el botón derecho del ratón, pero para que el ejemplo funcione sobre los tres navegadores, nuestro Control Menu Contextual , aparecerá cuando manteniendo pulsada la tecla “Ctrl” hagamos click con el raton. Al más puro estilo Mac.
El flujo de nuestra aplicación será el siguiente:
-
Identificamos las zonas o controles en las que queremos que aparezca el menú contextual.
-
Capturamos los eventos Click del raton sobre las zonas definidas. (Global a la aplicación, elementos o controles de usuario).
-
Creamos un objeto MenuContextual a partir de un Array de String con los textos que definin cada una de las opciones del menú.
Preparación de la aplicación Silverlight.
Como hemos identificado en el flujo anterior necesitamos definir las zonas sobre las que debe aparecer nuestro context menú, y esto no es mas que definir los controladores de eventos de raton sobre las zonas (elementos silvelight para nuestro ejemplo) en las que queremos que aparezca. En estos controladores básicamente lo que haremos será controlar si tenemos pulsada la tecla de “Control” y en tal caso, mostrar el menú contextual definido para esa area.
-
private void ejemploMenuCont_MouseLeftButtonUpCirculo(object sender,
-
MouseButtonEventArgs e)
-
{
-
//Si al soltar el boton del raton está pulsada la tecla Ctrl
-
if (ctr)
-
{
-
crearMenuCirculo();
-
}
-
else
-
{
-
ejemploMenuCont.Children.Remove(mt);
-
}
-
}
Evidentemente tenemos que controlar el evento keypress para detectar la tecla “Control”. Este evento lo controlaremos de manera global al usercontrol que define la pagina:
-
<usercontrol x:Class="AppMenuContextual.Page"></usercontrol>xmlns="http://schemas.microsoft.com/client/2007"
-
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-
Width="400" Height="440" KeyDown="ejemploMenuCont_KeyDown" KeyUp="ejemploMenuCont_KeyUp/>
Y el codigo sería tan simple como:
-
/// Evento Tecla Pulsada
-
private void ejemploMenuCont_KeyDown(object sender, KeyEventArgs e)
-
{
-
//Si es tecla control levantamos un flag
-
if (e.Key == Key.Ctrl)
-
ctr = true;
-
}
-
-
/// Evento soltar tecla
-
private void ejemploMenuCont_KeyUp(object sender, KeyEventArgs e)
-
{
-
ctr = false;
-
}
Accion de mostar el menú:
Esta acción la llevamos a cabo en el momento de contrastar que está pulsada la tecla Control y se ha hecho click sobre una zona valida. En función de la zona generamos un menú con unas opciones u otras. Veamos un ejemplo:
-
private void crearMenuCirculo()
-
{
-
if (mt != null)
-
ejemploMenuCont.Children.Remove(mt);
-
�
-
-
opciones[0] = "Cambiar Color Circulo";
-
opciones[1] = "Crear Rectangulo";
-
opciones[2] = "Crear Circulo";
-
opciones[3] = "Cambiar Fondo";
-
opciones[4] = "Acerca de ...";
-
-
mt.SetValue(Canvas.TopProperty, posicionClick.Y);
-
mt.SetValue(Canvas.LeftProperty, posicionClick.X);
-
ejemploMenuCont.Children.Add(mt);
-
}
En esta funcion hacemos lo siguiente:
-
Borramos el objeto menu de la pagina.
-
Creamos un lista de opciones.
-
Genermos un objeto menu contextual.
-
Le establecemos las coordenas de posicion.
-
Le indicamos el metodo que va capturar el evento publico que va a lanzar el objeto context menu.
-
Añadimo el menu contextual a la pagina.
Ejecutar Acción elegida:
Para llevar a cabo esta función (punto número 6 del flujo anteriormente descrito), definimos un método que recibe como parámetro un objeto de la clase MenuContextualEventArg, el cual nos va a indcar que opción ha sido elegida.
-
private void OpcionMenuElegidaContenedor(object sender,
-
MenuContextualEventArg argumentos)
-
{
-
txtSalida.Text = argumentos.Valor;
-
-
switch (argumentos.Posicion)
-
{
-
case 0:
-
LimpiarContenedor();
-
break;
-
case 1:
-
CambiarColor(fondoContenedor); �
-
break; �
-
}
-
ejemploMenuCont.Children.Remove(mt);
-
}
Comunicación Entre el objeto Menu contextual y el UserControl Contenedor
Desde nuestra aplicación sabemos cuando debemos mostrar nuestro menu contextual y donde, pero una vez hemos hecho esto perdemos el control sobre el funcionamiento del mismo. De alguna manera debemos de saber si se ha elegido una opción, y en tal caso, conocer cual ha sido.
Este proceso se ha llevado a cabo, mediante la definicion de un Evento Publico y su delegado en la Clase MenuContextual. En la clase que define el userControl menú contextual tenemos algo tal que asi:
-
/// Evento Publico del control "Menu Contextual" para indicar
-
/// que se ha seleccionado una opcion del menu
-
public event MenuContextualEventHandler OpcionSeleccionada;
-
public delegate void MenuContextualEventHandler(object sender,
-
MenuContextualEventArg argumentos);
-
-
/// Accion que genera un evento indicando que se ha seleccionado
-
/// una opcion del menu
-
void Opcion_MouseClick(object sender, MouseButtonEventArgs e)
-
{
-
TextBox t = (TextBox)sender;
-
if (OpcionSeleccionada != null)
-
}
Primeramente definimos el evento público que se puede lanzar desde el control.
Mas adelante, en la definición del evento OnClick, una vez hemos comprobado que ha sido asignado un manejador de eventos para nuestro evento, lanzamos el evento.
Objeto Menu Contextual
Además de lo comentado anteriormente, se genera una opción por cada uno de los valores del array que recibe como parámetro en el constructor del userControl Menú Contextual, y también se hace un control de la posición del ratón para resaltar la opción sobre la que se encuentra este.
He aquí nuestro ejemplo en funcionamiento.
El código de este ejemplo lo puedes descargar aquí.
Recent Comments