TOC

This article has been localized into Polish by the community.

Audio i Wideo:

Stworzenie pełnego odtwarzacza dźwięku/wideo

W ostatnim rozdziale, obiecałem pokazać jak utworzyć się bardziej kompletny program, potrafiący obsługiwać zarówno pliki audio i wideo, wykorzystując fakt że klasa MediaPlayer/MediaElement ma wbudowaną w sobie obsługę tych plików.Jak zrobić kompletny odtwarzacz audio / video.

Będę korzystał z pojęć używanych w poprzednich rozdziałach o odtwarzaniu audio i wideo, aby włączyć je wszystkie do WPF Media Player. Wynik będzie wyglądać jak to :

Ale dotyczy to tylko sytuacji gdy odtwarzamy pliki audio / MP3. Po wczytaniu wideo interfejs automatycznie rozszerza się, aby wyświetlić treść wideo wewnątrz okna:

Pozwól mi trochę opowiedzieć jak to zostało zbudowane. Na końcu będziesz mógł, oczywiście, zobaczyć na cały źródłowy kod gotowy do uruchomienia.

Interfejs

Interfejs został podzielony na trzy pionowe obszary : górny, gdzie znajduje się pasek narzędziowy; środkowy, gdzie jest pokazywany film ( jeśli jest ładowany plik wideo ) i dolny, gdzie możemy znaleźć pasek stanu, całkowity czas trwania, Suwak do zobaczenia i kontrolowania postępu odtwarzania i ProgressBar na pokazujący głośność. Wszystkie te stosowane kontrolki zostały już wyjaśnione wcześniej w samouczku, tak więc nie będziemy się zbytnio na nich koncentrować.

Zauważ, że użyłem poleceń WPF, zamiast przypisania zdarzeń kliknięcia dla przycisków. To pozwala nam na łatwe ponowne użycie funkcjonalności w przypadku chcemy coś dodać np . w głównym menu lub menu kontekstowym. To również sprawia, że łatwiej będzie lub wyłączyć pewne funkcjonalność, w zależności od aktualnego stanu odtwarzacza.

Należy również zauważyć, że ustawiliśmy własność MediaElement Stretch na None, a okno SizeToContentMode na WidthAndHeight . To sprawia, że okno może zmniejszyć się do minimalnej wielkości niezbędnej, aby pokazać film, jeśli jestodtwarzany.

Dla pokazania głośności, wykorzystywaliśmy kontrolkę ProgressBar znajdującą się w dolnym , prawym rogu. Nie pozwala ona użytkownikowi kontrolować głośności, lecz jedynie pokazuje wartość Głośność, poprzez związanie wskaźnika z rzeczywistą wartością. Mamy wdrożony mały, ale schludny trick pozwalający użytkownikowi na kontrolę głośności- więcej na ten temat będzie poniżej .

Kod

W kodzie źródłowym, wykorzystaliśmy kilka technik już stosowanych w naszych poprzednich przykładach . Na przykład zainicjowaliśmy DispatcherTimer aby uruchamiał się co jedną sekundę i pokazywał aktualny czas odtwarzania. W zdarzeniu Tick timera aktualizujemy wartość Slider poprzez ustawienie Minimum ,Maksimum i aktualną Wartość zgodnie z odtwarzanym plikiem, a przez podpinania się do valueChanged(zmiana Wartości) zdarzenia na suwak , możemy użyć , że aby zaktualizować etykietę pokazano na prąd postęp odtwarzania w godzinach , minutach i sekundach .

Suwak sterujący również pozwala użytkownikowi przejść do innej części pliku, przez przeciągnięcie wskaźnikiem do innego miejsca. Obsługujemy to przez realizację wydarzeń DragStarted i DragCompleted – na początku ustawiamy zmienną ( userIsDraggingSlider ), która opowiada za to, że czasomierz nie aktualizuje się podczas przesuwania Suwaka, a potem przechodzimy do wyznaczonego fragmentu gdy użytkownik uwalnia się myszką przycisk .

Mamy tu procedury CanExecute i Executed dla obsługi czterech komend, najbardziej interesujące są komendy Pauza i Stop. Ponieważ my nie możemy dowiedzieć się aktualnego stanu MediaElement, musimy sami go pamiętać i śledzić. Zrobione jest to poprzez lokalną zmienną o nazwie mediaPlayerIsPlaying , która regularnie sprawdzamy aby zobaczyć czy Pauza Stop i przyciski powinny być włączone .

Ostatni mały szczegół na który warto zwrócić uwagę to zdarzenie Grid_MouseWheel . Informacje o tym zdarzeniu otrzymujemy gdy użytkownik poruszy kółko myszy. Po tego zdarzenia przypisujemy możliwość zmiany głośności. Zależnie od kierunku ( dowiadujemy się o tym poprzez własność Delta, która jest ujemna, gdy przewijanie w dół i dodatnia, gdy przewijanie w górę ). To jest natychmiast odzwierciedlenie w interfejsie użytkownika, kontrolka ProgressBar jest związana z wartości określającą głośność w MediaElement .

Kompletny kod źródłowy

Z całą teorią opisaną powyżej, oto kompletny kod źródłowy.

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

	}
}

Podsumownie

Kod programu może wydawać się nieco przytłaczający, ale jak możcie zobaczyć, istnieje w nim wiele powtórzeń. Jeśli to przeanalizujesz to wkrótce przekonasz się, że stworzenie całkiem dobrego multimedialnego odtwarzacza w WPF nie jest naprawdę trudne! Nie miej żadnych oporów, aby zastosować go w swoich własnych projektach - np. zaimplementowanie funkcji list nagrań ?


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!