Silverlight 4 Beta – Soporte para Arrastrar y Soltar
Posted on : 25-11-2009 | By : Rodrigo | In : Silverlight 4
Tags: AllowDrop, Drop, IDataObject, Silverlight 4
3
Silverlight 4 cuenta con soporte de arrastrar uno o varios archivos desde afuera de la aplicación hacia adentro de ella y soltarlo(s) para poder leer su información y contenido. Esta característica nos permite como desarrolladores crear mejores Experiencias para los Usuarios ya que evitan el número de cajas de diálogo y clics para abrir o leer un archivo o conjunto de archivos. En este artículo veremos a detalle esta nueva funcionalidad, por medio de una aplicación capaz de reproducir archivos de audio y video (MP3 y WMV respectivamente).
El proyecto
Iniciaremos creando un nuevo proyecto de Silverlight 4 por medio de Visual Studio 2010 Beta 2. Al proyecto lo nombraremos Demo.SL4.ArrastrarSoltar y aceptaremos las opciones por default para crear un proyecto Web para probar la aplicación Silverlight. En MainPage.xaml agregaremos algunos elementos y controles para tener la siguiente Interfaz de Usuario:
De la interface podemos destacar lo siguiente:
-Implementamos un MediaElement llamado media (no visible en la figura anterior) el cual nos servirá para reproducir el audio o video.
-El área gris obscura es un Rectangle llamado rectangulo el cual nos servirá como área para poder arrastrar un archivo.
-El área gris clara es un ListBox, en donde se mostrarán el (los) archivo(s) de audio y/o video que se arrastren desde afuera de la aplicación.
-La barra de botones de abajo nos servirán para controlar el MediaElement en donde se reproducirán los archivos.
El código completo de MainPage.xaml es el siguiente:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="800">
<UserControl.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground"
Value="White" />
<Setter Property="HorizontalAlignment"
Value="Center" />
<Setter Property="VerticalAlignment"
Value="Center" />
</Style>
<Style TargetType="Button">
<Setter Property="Width"
Value="100" />
<Setter Property="Height"
Value="30" />
<Setter Property="VerticalAlignment"
Value="Center" />
<Setter Property="HorizontalAlignment"
Value="Center" />
<Setter Property="Margin"
Value="3" />
</Style>
<Storyboard x:Name="VideoStoryboard">
<DoubleAnimation Storyboard.TargetName="media"
Storyboard.TargetProperty="Width"
From="0"
To="400"
Duration="00:00:02">
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="media"
Storyboard.TargetProperty="Height"
From="0"
To="300"
Duration="00:00:02">
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Name="ImagenStoryboard">
<DoubleAnimation Storyboard.TargetName="imagen"
Storyboard.TargetProperty="Width"
From="150"
To="200"
Duration="00:00:01"
AutoReverse="True"
RepeatBehavior="Forever"
>
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="imagen"
Storyboard.TargetProperty="Height"
From="50"
To="100"
Duration="00:00:01"
AutoReverse="True"
RepeatBehavior="Forever"
>
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="Black">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<TextBlock Text="Silverlight 4 Beta – Arrastrar y Soltar" FontSize="18" FontWeight="Bold" Grid.ColumnSpan="2" />
<Rectangle Grid.Row="1" Fill="Gray" x:Name="rectangulo" AllowDrop="True" />
<MediaElement x:Name="media" Width="0" Height="0" Stretch="Uniform"
Grid.Row="1" AutoPlay="True"
Volume="1"
AllowDrop="True"
/>
<Image x:Name="imagen"
Width="0"
Height="0"
Stretch="Uniform"
Source="partitura.jpg"
Grid.Row="1" />
<ListBox x:Name="lista"
Grid.Row="1"
Grid.Column="1"
Background="LightGray"
AllowDrop="True"
>
</ListBox>
<StackPanel Grid.Row="2" Grid.ColumnSpan="2">
<TextBlock x:Name="fileInfo" Text="Instrucciones: Arrastra un archivo .MP3 o .WMV a las áreas grises" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="Iniciar" x:Name="btnPlay" IsEnabled="False" />
<Button Content="Pausa" x:Name="btnPause" IsEnabled="False" />
<Button Content="Parar" x:Name="btnStop" IsEnabled="False"/>
<Button Content="Limpiar lista"
x:Name="btnClear" IsEnabled="{Binding Items.Count, ElementName=lista}"/>
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
Propiedad AllowDrop
La propiedad para determinar si algún elemento es capaz de recibir un archivo que se está arrastrando desde afuera de la aplicación es la propiedad AllowDrop. Esta propiedad está habilitada en nuestra aplicación para el rectángulo, el ListBox y el MediaElement, ya que será cualquiera de esos elementos capaz de “recibir” un archivo que se esté soltando después de haberlo arrastrado desde afuera de la aplicación. Podemos establecerla desde Xaml o programáticamente.
Evento Drop
El evento más importante para el mecanismo de "soltar” un archivo desde afuera de la aplicación es el evento Drop. Este evento se disparará cuando efectivamente se haya soltado uno o varios archivos que provienen de afuera de la aplicación Silverlight. Drop es de tipo RoutedEvent, lo que significa que el evento una vez que suceda escalará de lo más profundo a lo más alto del árbol Xaml, por lo que será buena idea establecer su propiedad Handled a true para evitar que escale.
El objeto de argumentos de este evento es de tipo DragEventArgs en donde encontraremos –además de la propiedad Handled- la propiedad Data. Será en esta propiedad en donde podremos obtener la información del o los archivos que se han soltado en el elemento en cuestión.
Propiedad Data
Data es de tipo IDataObject. Por medio de su evento GetData() podremos obtener la información del o los archivos que se han soltado, siempre y cuando pasemos el formato adecuado a ese método. El formato para este mecanismo de Arrastrar y Soltar será “FileDrop” (también podremos usar DataFormas.FileDrop). El siguiente código muestra el manejador de evento llamado ManejaDrop, el cual manejará efectivamente los eventos Drop del rectángulo, del ListBox y del MediaElement:
{
//Obtiene el objeto que tiene la información del o los archivos soltados
IDataObject dataObject = e.Data;
//A través de GetData obtenemos un array de tipo FileInfo[]
//Este array tendrá tantos elementos como archivos se hayan soltado en el elemento
FileInfo[] fileInfoArray = dataObject.GetData("FileDrop") as FileInfo[];
//Carga la lista de archivos en el ListBox
CargarLista(fileInfoArray);
//Indicamos que el evento no escale
e.Handled = true;
}
Podemos apreciar la invocación a un método llamado CargarLista(). Este método recibe el array de FileInfo[] para cargar cada objeto de tipo FileInfo en el ListBox. El siguiente código muestra el método CargarLista():
{
//Establece FileInfo.Name como valor de cada elemento
lista.SelectedValuePath = "Name";
//Agrega los elementos a la lista
foreach (FileInfo item in archivos)
{
lista.Items.Add(item);
}
//Selecciona el elemento en la lista
lista.SelectedItem = lista.Items.Count == 0 ? lista.Items.First() : lista.Items.Last();
//Reproduce el archivo seleccionado
Play(lista.SelectedItem as FileInfo);
}
Finalmente, el método Play() se encarga de abrir el archivo en cuestión, establecerlo como fuente del MediaElement y por último reproducirlo. Play() incluye la validación:
//Queremos obtener FullName si es que está ejecutando con Confianza Elevada
if (!Application.Current.HasElevatedPermissions)
info = string.Format("Nombre: {0} | Tamaño: {1}", archivo.Name, archivo.Length);
ya que es buena idea obtener la información de la ruta física real si es que la aplicación está ejecutando en Confianza Elevada.
Resultado
En las siguientes figuras vemos la aplicación en acción (dentro del navegador) en este caso estamos arrastrando 11 archivos .mp3 al ListBox:
Una vez soltados los archivos, se cargan en el ListBox y comienza la reproducción del archivo seleccionado:
Resumen
La propiedad AllowDrop permite que un elemento en Silverlight pueda ser capaz de recibir un archivo que se esté arrastrando desde afuera de la aplicación. Esto nos evita el uso de la caja de diálogo OpenFileDialog() además de poder brindar una mejor experiencia a nuestros usuarios con características esperadas y naturales.
Pueden descargar el código aquí.
Pueden ver el demo en vivo aquí (requiere Silverlight 4).




[...] Ver artículo completo aquí [...]
[...] En el artículo anterior vimos que una de las características nuevas de Silverlight 4 es su capacidad de recibir archivos que se estén arrastrando desde afuera de la aplicación. No obstante, en Mac OS X es diferente el mecanismo para lograr esta funcionalidad ya que en ese sistema operativo, una acción de arrastrar y soltar no le avisa al API de Silverlight de lo ocurrido, a diferencia de lo que sucede en Windows. En este artículo veremos la alternativa para implementar esta característica en Mac OS X. Cabe mencionar que este mecanismo funcionará en Safari, mientras que en FireFox sea probable que no debido a la diferencia de arquitectura de este último en el sistema operativo de Apple. [...]
[...] En el artículo anterior vimos que una de las características nuevas de Silverlight 4 es su capacidad de recibir archivos que se estén arrastrando desde afuera de la aplicación. No obstante, en Mac OS X es diferente el mecanismo para lograr esta funcionalidad ya que en ese sistema operativo, una acción de arrastrar y soltar no le avisa al API de Silverlight de lo ocurrido, a diferencia de lo que sucede en Windows. En este artículo veremos la alternativa para implementar esta característica en Mac OS X. [...]