TOC

This article has been localized into Czech by the community.

Audio a video:

Návod: Vytvoření kompletního audio/video přehrávače

Jako závěr posledních kapitol o přehrávání audia a videa jsem se rozhodl vytvořit ucelenější vzorek, kde využijeme skutečnosti, že třídy MediaPlayer/MediaElement mohou zpracovávat jak audio, tak video.

Vezmu koncepty použité v článcích o přehrávání audia a videa a spojím je s několika ovládacími prvky, o kterých jsme již dříve diskutovali v tomto článku, a všechno to proměním ve WPF Media Player. Výsledek bude vypadat nějak takto:

Ale to je pouze, když přehrává audio/MP3 soubory. Jakmile je načteno video, rozhraní se automaticky rozšíří a ukáže video obsah uvnitř okna:

Dovolte mi říct vám něco o tom, jak byla tato věc postavena. Nakonec samozřejmě uvidíte celý zdrojový kód, připravený, abyste si s ním mohli hrát.

Rozhraní

Rozhraní bylo rozděleno do tří vertikálních oblastí: Vrchní, kde se nachází panel nástrojů, střední, kde se zobrazuje video (pokud je načten soubor videa), a spodní, kde najdeme stavový řádek, kompletní s časovým stavem, posuvníkem Slider pro sledování a ovládání postupu a ProgressBar pro zobrazení hlasitosti. Všechny ovládací prvky použité zde byly vysvětleny již dříve v tutoriálu, takže se na to nebudeme příliš zaměřovat.

Všimněte si použití příkazů WPF namísto událostí kliknutí pro tlačítka. To nám umožňuje snadno znovu použít funkcionalitu v případě, že bychom chtěli přidat například hlavní menu nebo kontextové menu s některou ze stejných funkcionalit. Také to usnadňuje zapínání a vypínání funkcionalit, v závislosti na aktuálním stavu přehrávače.

Dále si všimněte, že jsme nastavili vlastnost Stretch prvků MediaElement na None a vlastnost SizeToContentMode okna na WidthAndHeight. To je to, co udržuje okno na minimální velikosti potřebné k zobrazení rozhraní i videa, pokud je nějaké přehráváno.

Pro zobrazení hlasitosti jsme použili ovládací prvek ProgressBar v pravém dolním rohu. Tento momentálně neumožňuje uživateli ovládat hlasitost, ale pouze odráží vlastnost Volume na ovládacím prvku MediaElement, prostřednictvím klasické datové vazby (data bindingu). Přesto jsme implementovali malý, ale šikovný trik, který uživateli umožňuje ovládat hlasitost - více o tom níže.

Kód

V kódu na pozadí opětovně využíváme několik technik, které jsme již použili v našich předchozích příkladech. Například spouštíme DispatcherTimer a necháme ho tikat každou sekundu, aby zobrazil aktuální postup přehrávání v rozhraní. V události Tick časovače aktualizujeme ovládací prvek Slider, nastavíme Minimum, Maximum a aktuální Hodnotu podle přehrávaného souboru a propojením s událostí ValueChanged na posuvníku to používáme k aktualizaci štítku zobrazujícího aktuální postup přehrávání v hodinách, minutách a sekundách.

Ovládací prvek Slider také umožňuje uživateli přeskočit na jinou část souboru, jednoduše přetažením "jezdce" na jiné místo. To zpracováváme implementací událostí pro DragStarted a DragCompleted – první z nich nastaví proměnnou (userIsDraggingSlider), která říká časovači, aby během táhnutí neaktualizoval Slider, a druhá umožní přeskočit na určenou část, když uživatel uvolní tlačítko myši.

Existují obslužné rutiny CanExecute a Executed pro čtyři příkazy, které používáme, a zejména ty pro Pause (Pauza) a Stop (Zastavit) jsou zajímavé. Jelikož nemůžeme získat aktuální stav z ovládacího prvku MediaElement, musíme sledovat aktuální stav sami. To se děje pomocí lokální proměnné nazvané mediaPlayerIsPlaying, kterou pravidelně kontrolujeme, abychom zjistili, zda by měla být tlačítka Pause a Stop povolena.

Poslední malý detail, kterého byste si měli všimnout, je událost Grid_MouseWheel. Hlavní Grid pokrývá celé okno, takže přihlášením k této události jsme informováni, když uživatel otáčí kolečkem myši. Když k tomu dojde, jako malý vtip, zesílíme nebo ztlumíme hlasitost v závislosti na směru (zjistíme to podle vlastnosti Delta, která je záporná při posouvání dolů a kladná při posouvání nahoru). To se okamžitě odráží v uživatelském rozhraní, kde je ovládací prvek ProgressBar svázán s vlastností Volume ovládacího prvku MediaElement.

Kompletní zdrojový kód

S veškerou teorií k popsanému příkladu, přikládám úplný zdrojový kód:

<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;
		}

	}
}

Shrnutí

Výpis kódu může vypadat trochu přesyceně, ale jak můžete vidět, obsahuje mnoho opakování. Když to posoudíte, brzy pochopíte, že vytvoření poměrně schopného přehrávače médií ve WPF opravdu není tak těžké! Neváhejte na tomto příkladu stavět vaše vlastní projekty – co třeba implementovat funkci playlistu?


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!