TOC

This article has been localized into Italian by the community.

Audio e Video:

How-to: Create un riproduttore Audio/Video completo

Come conclusione degli ultimi capitoli sulla riproduzione audio e video, ho deciso di creare un esempio più completo, dove possiamo trarre vantaggio dal fatto che le classi MediaPlayer e MediaElement possano gestire sia audio sia video.

Estrarrò i concetti usati negli articoli sulla riproduzione audio e video e li combinerò con diversi controlli di cui abbiamo già discusso precedentemente in questo articolo, e li trasformerò in un Media Player WPF. Il risultato assomiglierà a questo:

Ma così è solo quando riproduce file audio ed MP3. Quando viene caricato un video, l'interfaccia si espande automaticamente per mostrare il video all'interno della finestra:

Lasciami spiegare come ho ottenuto questo risultato. Alla fine, potrai certamente vedere l'intero codice sorgente, pronto da provare.

L'interfaccia

L'interfaccia è stata divisa in tre aree verticali: la parte superiore, dove è collocata la toolbar, il centro, dove il video viene mostrato (se è stato caricato un file video), e la parte inferiore, dove troviamo la barra di stato, abbinata ad una barra temporale, uno Slider per vedere e controllare l'avanzare della riproduzione e una ProgressBar per mostrare il volume. Tutti i controlli utilizzati qui sono già stati spiegati precedentemente nel tutorial, così non ci concentreremo troppo su questo.

Nota l'uso dei comandi WPF, al posto degli eventi click per i bottoni. Questo ci permette di riutilizzare facilmente la funzionalità nel caso in cui vogliamo aggiungere, per esempio, un menu principale o un menu contestuale con le medesime funzionalità. Rende anche più facile attivare o disattivare la funzionalità, a seconda dello stato corrente del riproduttore.

Nota anche che abbiamo impostato la proprietà Stretch del MediaElement a None, e la proprietà SizeToContentMode della Window a WidthAndHeight. Questo manterrà la finestra alla dimensione minima necessaria per mostrare sia l'interfaccia sia il video, nel caso in cui un video sia riprodotto.

Per mostrare il volume, abbiamo usato un controllo ProgressBar nell'angolo inferiore destro. Questo controllo non permette all'utente di controllare il volume, ma semplicemente riflette la proprietà Volume del controllo MediaElement, attraverso un classico data binding. Comunque, abbiamo implementato un trucco piccolo ma efficace per permettere all'utente di controllare il volume - più sotto trovate la descrizione.

Il codice

Nel code behind, abbiamo riutilizzato diverse tecniche già usate nei precedenti esempi. Per esempio, abbiamo istanziato un DispatcherTimer e l'abbiamo fatto scattare ogni secondo, per mostrare l'avanzamento della riproduzione nell'interfaccia. Nell'evento Tick del timer, aggiorniamo il controllo Slider, impostando Minimum, Maximum e Value corrente a seconda del file riprodotto, e agganciando l'evento ValueChanged dello slider, possiamo aggiornare la label con ore, minuti e secondi della riproduzione corrente.

Il controllo Slider permette inoltre all'utente di saltare ad un'altra parte del file, semplicemente trascinando la "levetta" in un'altra posizione. Questo è gestito implementando gli eventi DragStarted e DragCompleted - il primo imposta una variabile (userIsDraggingSlider) che fa in modo che il timer non aggiorni lo slider mentre lo trasciniamo, e il secondo salta alla parte scelta del file quando l'utente rilascia il pulsante del mouse.

Ci sono gestori per CanExecute ed Executed dei quattro comandi che usiamo e quelli per la pausa e lo stop sono interessanti. Poiché non possiamo recuperare lo stato corrente dal controllo MediaElement, dobbiamo noi tener traccia dello stato corrente. Questo scopo è raggiunto dalla variabile locale chiamata mediaPlayerIsPlaying, che controlliamo regolarmente per abilitare correttamente i pulsanti pausa e stop.

L'ultimo dettaglio che dovresti notare è l'evento Grid_MouseWheel. La grid principale ricopre l'intera finestra, così, sottoscrivendo l'evento, riceviamo notifiche qando l'utente usa la rotellina del mouse. Quando accade, ecco il trucchetto, alziamo o abbassiamo il volume, a seconda della direzione di movimento (lo otteniamo osservando la proprietà Delta, che è negativa per lo scorrimento verso il basso e positiva per lo scorrimento verso l'alto). Questo viene immediatamente riflesso nell'interfaccia utente, dove il controllo ProgressBar è bindato al proprietà Volume del MediaElement.

Il codice sorgente completo

Dopo aver spiegato tutta la teoria dietro l'esempio, ecco il codice sorgente 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;
		}

	}
}

Riepilogo

Il listato può sembrare molto lungo, ma, come puoi vedere, ci sono molte ripetizioni. Se dai un'occhiata all'immagine, ti renderai presto conto che creare un media player completo in WPF non è così difficile! Sentiti libero di ampliare questo esempio per i tuoi progetti - perché non aggiungere una funzionalità playlist?


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!