none
如何利用WPF中的MediaElement控件实现AB循环播放的功能? RRS feed

  • 问题

  • 我正在帮同学做一个简陋的AB循环播放器来解决他学习英语中遇到的需要反复听某一个单词的需求。

    我刚刚开始接触WPF和C#(我有一定的C++和OOP的基础),感觉上手还是挺快的,很快实现了播放的功能,但是在实现AB点循环播放的时候不知道如何实现,我打算用TimeSpan来获得两个时间节点,然后再循环播放这两个节点之间的音频,可是实现的时候遇到了变量的作用范围的问题,在另外一个函数里面声明的节点在循环播放函数中无法引用这两个变量。

    想请问一下大家,实现AB循环播放的大体思路是什么,如果能够贴出实现代码更好。

    接下来是我的C#代码。

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Windows.Data;
    using System.Windows.Media;
    using System.Windows.Input;
    
    namespace SDKSample
    {
    
        public partial class MediaElementExample : Page
        {
    
            // Play the media.
            void OnMouseDownPlayMedia(object sender, MouseButtonEventArgs args)
            {
    
                // The Play method will begin the media if it is not currently active or 
                // resume media if it is paused. This has no effect if the media is
                // already running.
                myMediaElement.Play();
    
                // Initialize the MediaElement property values.
                InitializePropertyValues();
    
            }
    
            // Pause the media.
            void OnMouseDownPauseMedia(object sender, MouseButtonEventArgs args)
            {
    
                // The Pause method pauses the media if it is currently running.
                // The Play method can be used to resume.
                myMediaElement.Pause();
    
            }
    
            // Stop the media.
            void OnMouseDownStopMedia(object sender, MouseButtonEventArgs args)
            {
    
                // The Stop method stops and resets the media to be played from
                // the beginning.
                myMediaElement.Stop();
    
            }
    
            // Change the volume of the media.
            private void ChangeMediaVolume(object sender, RoutedPropertyChangedEventArgs<double> args)
            {
                myMediaElement.Volume = (double)volumeSlider.Value;
            }
    
            // Change the speed of the media.
            private void ChangeMediaSpeedRatio(object sender, RoutedPropertyChangedEventArgs<double> args)
            {
                myMediaElement.SpeedRatio = (double)speedRatioSlider.Value;
            }
    
            // When the media opens, initialize the "Seek To" slider maximum value
            // to the total number of miliseconds in the length of the media clip.
            private void Element_MediaOpened(object sender, EventArgs e)
            {
                timelineSlider.Maximum = myMediaElement.NaturalDuration.TimeSpan.TotalMilliseconds;
            }
    
            // When the media playback is finished. Stop() the media to seek to media start.
            private void Element_MediaEnded(object sender, EventArgs e)
            {
                myMediaElement.Stop();
            }
    
            // Jump to different parts of the media (seek to). 
            private void SeekToMediaPosition(object sender, RoutedPropertyChangedEventArgs<double> args)
            {
                int SliderValue = (int)timelineSlider.Value;
    
                // Overloaded constructor takes the arguments days, hours, minutes, seconds, miniseconds.
                // Create a TimeSpan with miliseconds equal to the slider value.
                TimeSpan ts = new TimeSpan(0, 0, 0, 0, SliderValue);
                myMediaElement.Position = ts;
            }
    
            void InitializePropertyValues()
            {
                // Set the media's starting Volume and SpeedRatio to the current value of the
                // their respective slider controls.
                myMediaElement.Volume = (double)volumeSlider.Value;
                myMediaElement.SpeedRatio = (double)speedRatioSlider.Value;
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                //open the local file and get it path
                Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
                dlg.Title = "select a file";
                dlg.Filter = "mp4 file|*.mp4|mp3 file|*.mp3|所有文件|*.*";
                dlg.FileName = string.Empty;
                dlg.FilterIndex = 1;
                dlg.RestoreDirectory = true;
                dlg.DefaultExt = ".mp4";
                string fileName;
                Nullable<bool> result = dlg.ShowDialog();
                //play the mp4 or mp3 file
                if (result == true)
                {
                    fileName = dlg.FileName;
                    Uri myUri = new Uri(fileName);
                    myMediaElement.Source = myUri;
                    myMediaElement.Play();
                }
            }
    
            private void Button_Click_1(object sender, RoutedEventArgs e)
            {
                //get timepoint A
                TimeSpan tsA;
                tsA = myMediaElement.Position;
            }
    
            private void Button_Click_2(object sender, RoutedEventArgs e)
            {
                //get timepoint B
                TimeSpan tsB;
                tsB = myMediaElement.Position;
            }
    
            private void Button_Click_3(object sender, RoutedEventArgs e)
            {
                //play point A to point B in roll 
                myMediaElement.Stop();
                myMediaElement.Position = tsA;      //wrong
                //TO DO
            }
    
        }
    }
    接下来是我的Xaml代码。
    <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="SDKSample.MediaElementExample" >
    
        <StackPanel Background="Black" Height="378" Width="534">
    
            <!-- To interactively stop, pause, and play the media, the LoadedBehavior 
               property of the MediaElement must be set to "Manual". -->
            <MediaElement Source="media\numbers.wmv" Name="myMediaElement" 
         Width="450" Height="250" LoadedBehavior="Manual" UnloadedBehavior="Stop" Stretch="Fill" 
         MediaOpened="Element_MediaOpened" MediaEnded="Element_MediaEnded"/>
            <Button Content="A point" Margin="230,0" HorizontalContentAlignment="Center" Click="Button_Click_1"/>
            <Button Content="B point" Margin="230,0" Click="Button_Click_2"/>
    
            <StackPanel HorizontalAlignment="Center" Width="450" Orientation="Horizontal">
    
                <!-- Play button. -->
                <Image Source="images\UI_play.gif" MouseDown="OnMouseDownPlayMedia" Margin="5" />
    
                <!-- Pause button. -->
                <Image Source="images\UI_pause.gif" MouseDown="OnMouseDownPauseMedia" Margin="5" />
    
                <!-- Stop button. -->
                <Image Source="images\UI_stop.gif" MouseDown="OnMouseDownStopMedia" Margin="5" />
    
                <!-- Volume slider. This slider allows a Volume range between 0 and 1. -->
                <TextBlock Foreground="White" VerticalAlignment="Center" Margin="5"  >Volume</TextBlock>
                <Slider Name="volumeSlider" VerticalAlignment="Center" ValueChanged="ChangeMediaVolume" 
           Minimum="0" Maximum="1" Value="0.5" Width="70"/>
    
                <!-- Volume slider. This slider allows you to change the speed of the media playback. -->
                <TextBlock Foreground="White" Margin="5"  VerticalAlignment="Center">Speed</TextBlock>
                <Slider x:Name="speedRatioSlider" VerticalAlignment="Center" ValueChanged="ChangeMediaSpeedRatio" 
           Value="1" Width="70" />
    
                <!-- Seek to slider. Ths slider allows you to jump to different parts of the media playback. -->
                <TextBlock Foreground="White" Margin="5"  VerticalAlignment="Center">Seek To</TextBlock>
                <Slider Name="timelineSlider" Margin="5" ValueChanged="SeekToMediaPosition" Width="70"/>
    
            </StackPanel>
            <Button Content="open file" Width="74" Click="Button_Click" Margin="231,0,0,0" HorizontalAlignment="Left"/>
            <Button Content="AGAIN" Click="Button_Click_3"/>
        </StackPanel>
    </Page>

    希望能够给出实现代码或实现思路,如果我的代码中有可以优化的地方,也欢迎指出。

    2014年6月3日 17:01

答案

  • 徐通,你好!

    在WPF中实现对MediaElement循环播放可以这样来操作。我把这个Sample简化了一下。播放MP3, WMV格式的音频是OK的。请注意加粗的代码。

    XAML:

    <Window x:Class="WpfMediaPlayer.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Media Player" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="320*"/>
                <RowDefinition Height="50*"/>
            </Grid.RowDefinitions>
            <MediaElement x:Name="MediaPlayer" Grid.RowSpan="1" LoadedBehavior="Manual" MediaEnded="MediaPlayer_MediaEnded"/>
            <StackPanel Orientation="Horizontal" Grid.Row="1" HorizontalAlignment="Center">
                <Button x:Name="btnPlay" Content="Play" Click="btnPlay_Click" Width="50" Height="25" Margin="5"/>
                <Button x:Name="btnStop" Content="Stop" Click="btnStop_Click" Width="50" Height="25" Margin="5"/>
                <Button x:Name="btnMoveBack" Content="Back" Click="btnMoveBack_Click" Width="50" Height="25" Margin="5"/>
                <Button x:Name="btnMoveForward" Content="Forward" Click="btnMoveForward_Click" Width="50" Height="25" Margin="5"/>
                <Button x:Name="btnOpen" Content="Open" Click="btnOpen_Click" Width="50" Height="25" Margin="5"/>
            </StackPanel>
        </Grid>
    </Window>

    C# Code:

            public MainWindow()
            {
                InitializeComponent();
                IsPlaying(false);
            }
    
            private void IsPlaying(bool flag)
            {
                btnPlay.IsEnabled = flag;
                btnStop.IsEnabled = flag;
                btnMoveBack.IsEnabled = flag;
                btnMoveForward.IsEnabled = flag;
            }
    
            private void btnPlay_Click(object sender, RoutedEventArgs e)
            {
                IsPlaying(true);
                if (btnPlay.Content.ToString() == "Play")
                {
                    MediaPlayer.Play();
                    btnPlay.Content = "Pause";
                }
                else
                {
                    MediaPlayer.Pause();
                    btnPlay.Content = "Play";
                }
            }
    
            private void btnStop_Click(object sender, RoutedEventArgs e)
            {
                MediaPlayer.Pause();
                btnPlay.Content = "Play";
                IsPlaying(false);
                btnPlay.IsEnabled = true;
            }
    
            private void btnMoveBack_Click(object sender, RoutedEventArgs e)
            {
                MediaPlayer.Position -= TimeSpan.FromSeconds(10);
            }
    
            private void btnMoveForward_Click(object sender, RoutedEventArgs e)
            {
                MediaPlayer.Position += TimeSpan.FromSeconds(10);
            }
    
            private void btnOpen_Click(object sender, RoutedEventArgs e)
            {
                // Configure open file dialog box
                Microsoft.Win32.OpenFileDialog dialog = new Microsoft.Win32.OpenFileDialog();
                dialog.FileName = "Videos"; // Default file name
                //dialog.DefaultExt = ".WMV"; // Default file extension
                //dialog.Filter = "WMV file (.wm)|*.wmv"; // Filter files by extension 
    
                // Show open file dialog box
                Nullable<bool> result = dialog.ShowDialog();
    
                // Process open file dialog box results 
                if (result == true)
                {
                    // Open document 
                    MediaPlayer.Source = new Uri(dialog.FileName);
                    btnPlay.IsEnabled = true;
                }
            }
    
            private void MediaPlayer_MediaEnded(object sender, RoutedEventArgs e)
            {
                this.MediaPlayer.Position = TimeSpan.Zero;
                this.MediaPlayer.Play();
            }

    谢谢!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • 已标记为答案 徐通 2014年6月5日 9:22
    2014年6月4日 7:10
    版主
  • Hi,

    你把声明 Position A 与 Position B的语句放到方法体之外就可以访问.

    谢谢!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • 已标记为答案 徐通 2014年6月5日 9:21
    • 取消答案标记 徐通 2014年6月5日 9:21
    • 已标记为答案 徐通 2014年6月5日 9:21
    2014年6月5日 6:39
    版主

全部回复

  • 徐通,你好!

    在WPF中实现对MediaElement循环播放可以这样来操作。我把这个Sample简化了一下。播放MP3, WMV格式的音频是OK的。请注意加粗的代码。

    XAML:

    <Window x:Class="WpfMediaPlayer.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Media Player" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="320*"/>
                <RowDefinition Height="50*"/>
            </Grid.RowDefinitions>
            <MediaElement x:Name="MediaPlayer" Grid.RowSpan="1" LoadedBehavior="Manual" MediaEnded="MediaPlayer_MediaEnded"/>
            <StackPanel Orientation="Horizontal" Grid.Row="1" HorizontalAlignment="Center">
                <Button x:Name="btnPlay" Content="Play" Click="btnPlay_Click" Width="50" Height="25" Margin="5"/>
                <Button x:Name="btnStop" Content="Stop" Click="btnStop_Click" Width="50" Height="25" Margin="5"/>
                <Button x:Name="btnMoveBack" Content="Back" Click="btnMoveBack_Click" Width="50" Height="25" Margin="5"/>
                <Button x:Name="btnMoveForward" Content="Forward" Click="btnMoveForward_Click" Width="50" Height="25" Margin="5"/>
                <Button x:Name="btnOpen" Content="Open" Click="btnOpen_Click" Width="50" Height="25" Margin="5"/>
            </StackPanel>
        </Grid>
    </Window>

    C# Code:

            public MainWindow()
            {
                InitializeComponent();
                IsPlaying(false);
            }
    
            private void IsPlaying(bool flag)
            {
                btnPlay.IsEnabled = flag;
                btnStop.IsEnabled = flag;
                btnMoveBack.IsEnabled = flag;
                btnMoveForward.IsEnabled = flag;
            }
    
            private void btnPlay_Click(object sender, RoutedEventArgs e)
            {
                IsPlaying(true);
                if (btnPlay.Content.ToString() == "Play")
                {
                    MediaPlayer.Play();
                    btnPlay.Content = "Pause";
                }
                else
                {
                    MediaPlayer.Pause();
                    btnPlay.Content = "Play";
                }
            }
    
            private void btnStop_Click(object sender, RoutedEventArgs e)
            {
                MediaPlayer.Pause();
                btnPlay.Content = "Play";
                IsPlaying(false);
                btnPlay.IsEnabled = true;
            }
    
            private void btnMoveBack_Click(object sender, RoutedEventArgs e)
            {
                MediaPlayer.Position -= TimeSpan.FromSeconds(10);
            }
    
            private void btnMoveForward_Click(object sender, RoutedEventArgs e)
            {
                MediaPlayer.Position += TimeSpan.FromSeconds(10);
            }
    
            private void btnOpen_Click(object sender, RoutedEventArgs e)
            {
                // Configure open file dialog box
                Microsoft.Win32.OpenFileDialog dialog = new Microsoft.Win32.OpenFileDialog();
                dialog.FileName = "Videos"; // Default file name
                //dialog.DefaultExt = ".WMV"; // Default file extension
                //dialog.Filter = "WMV file (.wm)|*.wmv"; // Filter files by extension 
    
                // Show open file dialog box
                Nullable<bool> result = dialog.ShowDialog();
    
                // Process open file dialog box results 
                if (result == true)
                {
                    // Open document 
                    MediaPlayer.Source = new Uri(dialog.FileName);
                    btnPlay.IsEnabled = true;
                }
            }
    
            private void MediaPlayer_MediaEnded(object sender, RoutedEventArgs e)
            {
                this.MediaPlayer.Position = TimeSpan.Zero;
                this.MediaPlayer.Play();
            }

    谢谢!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • 已标记为答案 徐通 2014年6月5日 9:22
    2014年6月4日 7:10
    版主
  • Dear Jimmy Yang

    很感谢你的回答,我实验了你的代码,在朋友的帮助下把代码中的一个小BUG除掉了,发现你实现AB播放功能的思路是通过Back和Forward键来后退或前进一小部分内容实现循环播放,但是这样的实现有时候使用起来并不是很方便,因为不精确。

    我的答题思路是设置两个键,一个是A point键,另外一个是B point键,这两个键分别获得两个position,存储在变量里面,然后使用Again键来读取A position和B position,然后再循环播放两点之间的内容,不知您是否能满足我这个需求?还需要一个键,来退出当前的循环播放的状态,进行正常播放。

    再次感谢您的回答,也希望能有其他人帮我看一下这个问题应该如何解决。

    2014年6月4日 10:35
  • Hi,

    你把声明 Position A 与 Position B的语句放到方法体之外就可以访问.

    谢谢!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • 已标记为答案 徐通 2014年6月5日 9:21
    • 取消答案标记 徐通 2014年6月5日 9:21
    • 已标记为答案 徐通 2014年6月5日 9:21
    2014年6月5日 6:39
    版主
  • 谢谢您的提示,我现在已经做出AB播放器了

    祝身体健康,工作顺利!

    徐通

    2014年6月5日 9:21