事件MediaOpened无法提出

时间:2013-12-31 12:03:55

标签: c# wpf

我试图获得用户选择的音乐文件列表的自然持续时间。

    MediaElement getDetails;    //class variable
    private void AddMusictoList(List<music> pMusic)
    {
        getDetails = new MediaElement();  

        getDetails.MediaOpened += getDetails_MediaOpened;
        getDetails.MediaFailed += getDetails_MediaFailed;
        getDetails.LoadedBehavior = MediaState.Manual;
        Uri path;
        list = new music();
        foreach (music iMusic in pMusic)
        {
            path = new Uri(iMusic.path);
            list = iMusic; 
            getDetails.Source = path;
            getDetails.Play();
        }
    }
    //the function below is not called.why?
    private void getDetails_MediaOpened(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Hey");
        list.duration = getDetails.NaturalDuration.TimeSpan.ToString(@"hh\:mm\:ss");
        MessageBox.Show(list.duration);
        this.musicList.Items.Add(list);
    }


void getDetails_MediaFailed(object sender, ExceptionRoutedEventArgs e)
    {
        MessageBox.Show("Failed");
    }

未提出媒体已打开功能。我调试了代码。 getDetails.Source之后的自然持续时间保持不变(即设置为自动)并且没有timeSpan。为什么呢?

1 个答案:

答案 0 :(得分:2)

MediaElement未播放媒体,因为它尚未添加到用户界面。您的MediaElement是在代码隐藏中创建的,并存储在私有字段中;我认为用户永远不会看到它。

我在MediaElement documentation中找不到任何说明这一点的内容,但我确实发现媒体控件确实在我将其添加到Grid时开始播放媒体。

但是,当MediaElement添加到UI时,调用了Opened事件处理程序,但仅限于最后一个媒体文件。这是因为加载媒体的过程发生在后台,并且您的代码在此期间继续运行。因此,对于除最后一个之外的所有媒体文件,您最终会在通过要求加载下一个文件来完成加载一个文件之前中断MediaElement

为了改善目标,您一次只能加载一个媒体文件,当每个媒体文件完成加载时,开始加载下一个文件的过程:

    // New private field.  This enumerator stores our current position
    // iterating through the media files.
    private IEnumerator<music> files;

    private void AddMusictoList(List<music> pMusic)
    {
        this.files = pMusic.GetEnumerator();
        AddNextMusicFileIfExists();
    }

    // Starts loading the next file, if there is a next one.
    // If there isn't a next one, stops the media element.
    private void AddNextMusicFileIfExists()
    {
        if (this.files.MoveNext())
        {
            music iMusic = this.files.Current;
            Uri path = new Uri(iMusic.path);
            getDetails.Source = path;
            getDetails.Play();
        }
        else
        {
            getDetails.Stop();
        }
    }

    // I've replaced the MessageBoxes in this method with a call to
    // Debug.WriteLine, to prevent you getting spammed with lots of
    // message boxes.
    private void getDetails_MediaOpened(object sender, RoutedEventArgs e)
    {
        this.files.Current.duration = getDetails.NaturalDuration.TimeSpan.ToString(@"hh\:mm\:ss");
        System.Diagnostics.Debug.WriteLine(this.files.Current.duration);
        this.musicList.Items.Add(this.files.Current);
        AddNextMusicFileIfExists();
    }

这似乎有效,但有点慢。在一组35个MP3文件上运行大约需要3.8秒。这很可能是因为MediaElement正在加载整个媒体文件并开始解码其中的一些数据,以及确定文件的播放时间。

另一种方法是使用MediaPlayer类而不是MediaElement。这与MediaElement的行为方式大致相同,但不是控件,因此无法添加到XAML中。

如果您希望使用MediaPlayer代替MediaElement,则需要对代码进行一些更改:

  • 您拨打player.Open(uri)而不是getDetails.Source = uri
  • OpenedFailed事件处理程序使用EventArgs作为事件参数类型,而不是RoutedEventArgsExceptionRoutedEventArgs
  • 无需指定LoadedBehavior

我做了这些修改,并确认MediaPlayer的工作方式与我MediaElement的工作方式大致相同,包括同样令人沮丧的表现。我怀疑MediaElement正在使用MediaPlayer

如果您真正需要的媒体文件只是播放时间,那么使用MediaElementMediaPlayer不是您的最佳选择。相反,像TagLib#这样的库(请参阅this answer)可以快速加载标签元数据(艺术家,专辑,标题,播放时间等),而无需读取整个媒体文件。

编辑:添加了关于MediaPlayer的部分。

编辑2 :通常,要求Stack Overflow上的某人为您编写一些代码并不是一个好主意。但是,在这种情况下,我找不到TagLib#的任何文档;仅适用于它所基于的TagLib C ++库。所以这次我会例外。

如果您想使用TagLib#,您需要:

  • 在解决方案资源管理器中选择要添加TagLib#的项目。
  • 打开Package Manager控制台(Tools&gt; Library Package Manager&gt; Package Manager Console)并输入Install-Package taglib。这会下载TagLib#并将其添加到您的项目中。
  • 添加以下代码以确定曲目播放时间(假设music中有pMusic个对象列表:

        foreach (music iMusic in pMusic)
        {
            using (TagLib.File file = TagLib.File.Create(iMusic.path))
            {
                System.Diagnostics.Debug.WriteLine(
                        file.Properties.Duration.ToString(@"hh\:mm\:ss"));
            }
        }
    

这里我只是将输出写入Debug.WriteLine。这需要0.2秒才能在前面提到的同一组35个MP3文件上运行,这比使用MediaElement要快得多。