TOC

This article is currently in the process of being translated into Spanish (~99% done).

Audio y Vídeo:

How-to: Creating a complete Audio/Video player

Como conclusión a los capítulos anteriores sobre reproducción de vídeo y audio, he decidido crear un ejemplo más completo donde hacemos uso del hecho que las clases MediaPlayer/MediaElement pueden manejar tanto audio como vídeo.

Tomaré los conceptos utilizados en los artículos sobre reproducción de audio y vídeo y los combinaré con varios controles que hemos cubierto anteriormente en artículo, para convertirlo todo en un reproductor WPF. El resultado es algo parecido a esto:

Pero esto es solo cuando reproduces archivos de audio/MP3. Una vez un vídeo es cargado, la interfaz se expande automáticamente para mostrar el vídeo dentro de la ventana.

Dejadme explicaros un poco como ha sido construido. Al final podéis ver el código fuente, listo para jugar con él.

La interfaz

La interfaz ha sido dividida en tres áreas verticales: La superior, donde está localizada la barra de herramientas; la intermedia, donde el vídeo (si alguno ha sido cargado) se muestra; y la inferior, donde se encuentra la barra de estado, completa con un estado temporal, un Slider para ver y controlar el progreso y un ProgressBar para mostrar el volumen. Todos los controles utilizados han sido explicados previamente en este tutorial, así que no perderemos mucho tiempo en ello.

Fijaros en el uso de comandos WPF, en vez de eventos de click para los botones. Esto nos permitereutilizar la funcionalidad en caso que queramos añadir, por ejemplo, un menú principal o un menú de contexto con la misma funcionalidad. También nos facilita activar/desactivar la funcionalidad, dependiendo de el estado actual del reproductor.

Fijaos también que hemos seteado la propiedad del MediaElement Stretch a None, y la de la ventana SizeToContentMode a WidthAndHeight. Esto mantiene el tamaño mínimo de la ventana necesaria para mostrar la interfaz así como el vídeo, si alguno está siendo reproducido.

Para mostrar el volumen, hemos utilizado un control ProgressBar en la esquina inferior izquierda. Esto no permite al usuario controlar el volumen, simplemente refleja la propiedad Volume del MediaElement a través de un data binding clásico. Hemos implementado un pequeño truco ara permitir al usuario controlar el volumen - más sobre esto debajo.

El código

En el código debajo, reutilizamos varias técnicas ya utilizadas en ejemplos anteriores. Por ejemplo, iniciamos un DispatcherTimer y permite actualizarse cada segundo para mostrar el progreso de reproducción actual en la interfaz. En el evento Tick del contador, actualizamos el control Slider seteando Minimum, Maximum y Value relativos al archivo siendo reproducido; y registrándose al evento ValueChanged en el slider, actualizamos la etiqueta que muestra el progreso de reproducción actual en horas, minutos y segundos.

El control deslizante también permite al usuario saltar a otra parte del archivo, simplemente arrastrando el "pulgar" a otra ubicación. Manejamos esto implementando eventos para DragStarted y DragCompleted - el primero establece una variable ( userIsDraggingSlider ) que le dice al temporizador que no actualice el control deslizante mientras arrastramos , y el segundo para saltar a la parte designada cuando el usuario suelta el botón del ratón.

Hay CanExecute y controladores ejecutados para los cuatro comandos que usamos y especialmente los de Pausa y Detener son interesantes. Ya que no podemos obtener un estado actual del control MediaElement, tenemos que hacer un seguimiento del estado actual nosotros mismos. Esto se hace con una variable local llamada mediaPlayerIsPlaying , que verificamos regularmente para ver si los botones Pausa y Detener deben estar habilitados .

El último pequeño detalle que debe notar es el evento Grid_MouseWheel . La cuadrícula principal cubre toda la ventana, así que al suscribiéndonos a este evento, recibimos una notificación cuando el usuario desplaza la rueda. Cuando eso sucede, como un pequeño truco, subimos o bajamos el volumen, dependiendo de la dirección (lo obtenemos mirando la propiedad Delta, que es negativa al desplazarse hacia abajo y positiva al desplazarse hacia arriba). Esto se refleja inmediatamente en el      interfaz de usuario, donde un control ProgressBar está vinculado a la propiedad Volume del MediaElement.

El código fuente completo.

Con toda la teoría detrás del ejemplo descrito, aquí está el código fuente completo:

<Window x:Class="WpfTutorialSamples.Audio_and_Video.AudioVideoPlayerCompleteSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="WPF Media Player" Height="300" Width="300"
        MinWidth="300" SizeToContent="WidthAndHeight">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Open" CanExecute="Open_CanExecute" Executed="Open_Executed" />
        <CommandBinding Command="MediaCommands.Play" CanExecute="Play_CanExecute" Executed="Play_Executed" />
        <CommandBinding Command="MediaCommands.Pause" CanExecute="Pause_CanExecute" Executed="Pause_Executed" />
        <CommandBinding Command="MediaCommands.Stop" CanExecute="Stop_CanExecute" Executed="Stop_Executed" />
    </Window.CommandBindings>
    <Grid MouseWheel="Grid_MouseWheel">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <ToolBar>
            <Button Command="ApplicationCommands.Open">
                <Image Source="/WpfTutorialSamples;component/Images/folder.png" />
            </Button>
            <Separator />
            <Button Command="MediaCommands.Play">
                <Image Source="/WpfTutorialSamples;component/Images/control_play_blue.png" />
            </Button>
            <Button Command="MediaCommands.Pause">
                <Image Source="/WpfTutorialSamples;component/Images/control_pause_blue.png" />
            </Button>
            <Button Command="MediaCommands.Stop">
                <Image Source="/WpfTutorialSamples;component/Images/control_stop_blue.png" />
            </Button>
        </ToolBar>

        <MediaElement Name="mePlayer" Grid.Row="1" LoadedBehavior="Manual" Stretch="None" />

        <StatusBar Grid.Row="2">
            <StatusBar.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                    </Grid>
                </ItemsPanelTemplate>
            </StatusBar.ItemsPanel>
            <StatusBarItem>
                <TextBlock Name="lblProgressStatus">00:00:00</TextBlock>
            </StatusBarItem>
            <StatusBarItem Grid.Column="1" HorizontalContentAlignment="Stretch">
                <Slider Name="sliProgress" Thumb.DragStarted="sliProgress_DragStarted"  Thumb.DragCompleted="sliProgress_DragCompleted" ValueChanged="sliProgress_ValueChanged" />
            </StatusBarItem>
            <StatusBarItem Grid.Column="2">
                <ProgressBar Name="pbVolume" Width="50" Height="12" Maximum="1" Value="{Binding ElementName=mePlayer, Path=Volume}" />
            </StatusBarItem>
        </StatusBar>
    </Grid>
</Window>
using System;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Threading;
using Microsoft.Win32;

namespace WpfTutorialSamples.Audio_and_Video
{
	public partial class AudioVideoPlayerCompleteSample : Window
	{
		private bool mediaPlayerIsPlaying = false;
		private bool userIsDraggingSlider = false;

		public AudioVideoPlayerCompleteSample()
		{
			InitializeComponent();

			DispatcherTimer timer = new DispatcherTimer();
			timer.Interval = TimeSpan.FromSeconds(1);
			timer.Tick += timer_Tick;
			timer.Start();
		}

		private void timer_Tick(object sender, EventArgs e)
		{
			if((mePlayer.Source != null) && (mePlayer.NaturalDuration.HasTimeSpan) && (!userIsDraggingSlider))
			{
				sliProgress.Minimum = 0;
				sliProgress.Maximum = mePlayer.NaturalDuration.TimeSpan.TotalSeconds;
				sliProgress.Value = mePlayer.Position.TotalSeconds;
			}
		}

		private void Open_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = true;
		}

		private void Open_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			OpenFileDialog openFileDialog = new OpenFileDialog();
			openFileDialog.Filter = "Media files (*.mp3;*.mpg;*.mpeg)|*.mp3;*.mpg;*.mpeg|All files (*.*)|*.*";
			if(openFileDialog.ShowDialog() == true)
				mePlayer.Source = new Uri(openFileDialog.FileName);
		}

		private void Play_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = (mePlayer != null) && (mePlayer.Source != null);
		}

		private void Play_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			mePlayer.Play();
			mediaPlayerIsPlaying = true;
		}

		private void Pause_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = mediaPlayerIsPlaying;
		}

		private void Pause_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			mePlayer.Pause();
		}

		private void Stop_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = mediaPlayerIsPlaying;
		}

		private void Stop_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			mePlayer.Stop();
			mediaPlayerIsPlaying = false;
		}

		private void sliProgress_DragStarted(object sender, DragStartedEventArgs e)
		{
			userIsDraggingSlider = true;
		}

		private void sliProgress_DragCompleted(object sender, DragCompletedEventArgs e)
		{
			userIsDraggingSlider = false;
			mePlayer.Position = TimeSpan.FromSeconds(sliProgress.Value);
		}

		private void sliProgress_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
		{
			lblProgressStatus.Text = TimeSpan.FromSeconds(sliProgress.Value).ToString(@"hh\:mm\:ss");
		}

		private void Grid_MouseWheel(object sender, MouseWheelEventArgs e)
		{
			mePlayer.Volume += (e.Delta > 0) ? 0.1 : -0.1;
		}

	}
}

Resumen

La lista de códigos puede parecer un poco abrumadora, pero como puede ver, hay mucha repetición. Si quitas eso de la foto, pronto harás un reproductor multimedia bastante capaz en WPF pues no es realmente tan difícil! Siéntase libre de ampliar este ejemplo para tu propios proyectos: ¿qué tal implementar una función de lista de reproducción?


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!