TOC

This article has been localized into Vietnamese by the community.

Audio & Video:

Cách thực hiện: Tạo trình phát Audio / Video hoàn chỉnh

Để kết luận cho các chương cuối về phát âm thanh và video, tôi quyết định tạo một mẫu hoàn chỉnh hơn, trong đó chúng tôi tận dụng thực tế là các lớp MediaPlayer/MediaElement có thể xử lý cả âm thanh và video.

Tôi sẽ lấy các khái niệm được sử dụng trong các bài viết về cách phát âm thanh và video và kết hợp chúng với một số điều khiển mà chúng ta đã thảo luận trước đây trong bài viết này và biến tất cả thành WPF Media Player. Kết quả sẽ trông giống như thế này:

Nhưng đó chỉ là khi nó phát các tệp âm thanh / MP3. Khi video được tải, giao diện sẽ tự động mở rộng để hiển thị nội dung video bên trong cửa sổ:

Hãy để tôi nói cho bạn biết một chút về cách thức thứ này được xây dựng. Cuối cùng, bạn tất nhiên có thể thấy toàn bộ mã nguồn, phía dưới đây.

Giao diện

Giao diện đã được chia thành ba khu vực ngang: Trên cùng, nơi đặt thanh công cụ, giữa, nơi video (nếu tệp video được tải) được hiển thị và phía dưới, nơi chúng tôi tìm thấy một thanh trạng thái, hoàn thành với một trạng thái thời gian, Slider để xem và kiểm soát tiến trình và ProgressBar để hiển thị âm lượng. Tất cả các điều khiển được sử dụng ở đây đã được giải thích trước đây trong hướng dẫn, vì vậy chúng tôi sẽ không tập trung quá nhiều vào điều đó.

Lưu ý việc sử dụng các lệnh WPF, thay vì nhấp vào các sự kiện cho các buttons. Điều này cho phép chúng tôi dễ dàng sử dụng lại chức năng trong trường hợp chúng tôi muốn thêm, ví dụ: một menu chính hoặc một menu ngữ cảnh với một số chức năng tương tự. Nó cũng giúp chúng tôi dễ dàng bật và tắt chức năng hơn, tùy thuộc vào trạng thái hiện tại của người dùng.

Cũng lưu ý rằng chúng tôi đã đặt thuộc tính MediaElement Stretch thành None và Window SizeToContentMode thành WidthAndHeight. Đây là những gì giữ cho cửa sổ ở kích thước tối thiểu cần thiết để hiển thị giao diện cũng như video.

Để hiển thị Âm lượng, chúng tôi đã sử dụng điều khiển ProgressBar ở góc dưới bên phải. Điều này hiện không cho phép người dùng kiểm soát âm lượng, mà chỉ phản ánh thuộc tính Volume trên điều khiển MediaElement, thông qua một ràng buộc dữ liệu cổ điển. Mặc dù vậy, chúng tôi đã thực hiện một mẹo nhỏ nhưng gọn gàng để cho phép người dùng kiểm soát âm lượng - nhiều hơn về điều đó bên dưới.

Code

Trong Code-behind, chúng tôi sử dụng lại một số kỹ thuật đã được sử dụng trong các ví dụ trước. Chẳng hạn, chúng tôi khởi tạo một DispatcherTimer và để nó đánh dấu mỗi giây, để hiển thị tiến trình phát lại hiện tại trong giao diện. Trong sự kiện Tick của bộ đếm thời gian, chúng tôi cập nhật điều khiển Slider, bằng cách cài đặt giá trị Minimum, MaximumGiá trị hiện tại theo tệp đang được phát và bằng cách nối với sự kiện ValueChanged trên Slider, chúng tôi sử dụng điều đó để cập nhật nhãn hiển thị phát lại hiện tại trong giờ, phút và giây.

Điều khiển slider cũng cho phép người dùng bỏ qua phần khác của tệp, chỉ cần kéo "thumb" sang vị trí khác. Chúng tôi xử lý việc này bằng cách triển khai các sự kiện cho DragStartedDragCompleted - lần đầu tiên đặt biến (userIsDraggingSlider) để báo cho bộ đếm thời gian không cập nhật slider trong khi chúng tôi kéo và lần thứ hai bỏ qua phần được chỉ định khi người dùng nhả chuột.

Có các trình xử lý CanExecute và Executed cho bốn lệnh chúng ta sử dụng và đặc biệt là các lệnh cho Pause và Stop rất thú vị. Vì chúng tôi không thể có trạng thái hiện tại từ điều khiển MediaElement, chúng tôi phải tự theo dõi trạng thái hiện tại. Điều này được thực hiện với một biến cục bộ có tên là mediaPlayerIsPlaying, chúng tôi thường xuyên kiểm tra xem có nên bật nút Pause và Stop không.

Chi tiết nhỏ cuối cùng bạn nên chú ý là sự kiện Grid_MouseWheel. Grid chính bao phủ toàn bộ cửa sổ, vì vậy bằng cách đăng ký vào sự kiện này, chúng tôi nhận được thông báo khi người dùng scrolls the wheel. Khi điều đó xảy ra, như một mánh lới quảng cáo nhỏ, chúng tôi xoay âm lượng lên hoặc xuống, tùy thuộc vào hướng (chúng tôi nhận được điều đó bằng cách nhìn vào thuộc tính Delta, âm tính khi cuộn xuống và dương khi cuộn lên). Điều này ngay lập tức được phản ánh trong giao diện người dùng, trong đó điều khiển ProgressBar được liên kết với thuộc tính Volume của MediaElement.

Source code hoàn chỉnh

Với tất cả lý thuyết đằng sau ví dụ được mô tả, đây là source code hoàn chỉnh:

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

	}
}

Tổng kết

Danh sách code có thể trông hơi dài, nhưng như bạn có thể thấy, có rất nhiều sự lặp lại trong đó. Nếu bạn hiểu nó, bạn sẽ sớm nhận ra rằng việc tạo một trình phát đa phương tiện có khả năng khá lớn trong WPF thực sự không khó lắm! Vui lòng mở rộng ví dụ này cho các dự án của riêng bạn - làm thế nào về việc triển khai thêm tính năng danh sách phát?


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!