5

我正在创建一个具有播放功能的录音机控件。

我使用媒体元素播放录制的音频,如下所示:

using (var storage = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication())
{
    using (System.IO.Stream stream = new System.IO.IsolatedStorage.IsolatedStorageFileStream(filePath, System.IO.FileMode.Open, storage))
    {
        player.SetSource(stream);
    }
}

我面临的问题是,当我使用媒体元素播放录制的音频时。Stream 被锁定到媒体元素。我无法覆盖该文件,甚至无法再次播放它,因为该SetSource()方法会引发异常。

有没有办法强制媒体元素释放流?

4

4 回答 4

9

基于@Sheridan 回答这是我想出的有效方法。

每当MediaElement使用Stop()函数停止时,将Source属性设置为null如下所示:

ResetMediaElement()
{
    mediaElement.Stop();
    mediaElement.Source = null;
}

这将关闭附加到媒体元素的流,以便相关资源可以在其他地方使用。

于 2013-10-11T12:42:43.953 回答
2

如果您使用 MediaElement,请确保您不会被这个:http: //msdn.microsoft.com/en-us/library/cc626563 (v=vs.95).aspx

ArgumentNullException - mediaStreamSource 为空。
...

调用此方法后,MediaElement.Source 返回 null。如果调用此方法并设置了 MediaElement.Source,则最后一个操作获胜。

如果一个 MediaElement 从 UI 树中删除,而它有一个打开的 MediaStreamSource,则可能会忽略对 SetSource 的后续调用。为确保 featureSetSource 调用正常工作,请在从 UI 树中分离 MediaElement 之前将 Source 属性设置为 null。

自然会期望,如果他们只使用 SetSource(somestream) 来使用 SetSource(null) 来释放资源。不,他们认为“更好”,您必须使用 Source=null 来释放资源并且 SetSource(null) 抛出 ArgumentNullException

这就是我所说的设计错误(打破了“最不期望”行为的规则,并导致仅在运行时咬你的错误[除非有人制定了静态分析规则来捕捉这样的事情——当然需要元数据,一些论点不能为空,例如在代码合同中])

前几天我在ClipFlair Studio的 AudioRecorder 控件中重构一些代码时设法引入了这个错误:-(

请注意,您不能在 MediaElement 上使用Source = stream 之类的东西来打开 Stream,因为这是一个 Uri 属性(不是也接受 Stream 的 Object 属性),您必须改用SetSource (stream),所以您会还期望能够使用 SetSource(null) 来释放资源。

更新:在 AudioRecorderControl 的 AudioRecorderView 类(使用 MVVM 模式)中修复了此问题,在 Audio 属性的“set”访问器中,它需要以下空保护模式:

if (mediaStreamSource != null) 
  player.SetSource(mediaStreamSource); 
      //must set the source once, not every time we play the same audio, 
      //else with Mp3MediaSource it will throw DRM error 
else 
   player.Source = null; 
于 2014-12-12T03:23:06.873 回答
2
mediaElement.Stop();
mediaElement.ClearValue(MediaElement.SourceProperty);
于 2015-12-06T04:51:00.380 回答
0

I had a similar problem with displaying images. In a control with an image, I would get a 'File is in use' error whenever the user tried to update the image. The solution was to set the BitmapImage.CacheOption property to BitmapCacheOption.OnLoad:

MSDN says Set the CacheOption to BitmapCacheOption.OnLoad if you wish to close a stream used to create the BitmapImage. The default OnDemand cache option retains access to the stream until the image is needed, and cleanup is handled by the garbage collector.

After searching for a similar property that you could use for your MediaElement, it turns out that there isn't one. However, according to an answer on the chacheoption for mediaelement post from MSDN, there is a (long winded) way to achieve this... from the relevant answer:

I am not sure if your MediaElement is in an UserControl or not. but whatever the case you can set the UserControl or Control to IsEnabled=false, which in turn will trigger the Event Handler IsEnabledChanged. In it place the necessary code to stop the MediaElement from playback ME.Stop(), then call ME.Clear() and ME.Source = null. After that you should find no problems to delete the source file.

ME.Source = new Uri(MediaFilePath);
ME.Play();
...
private void DeleteButton_Click(object sender, RoutedEventArgs e) 
{ 
    ME.IsEnabled = false;   // This will call the Event Handler IsEnabledChanged 
    System.IO.File.Delete(MediaFilePath); 
    // Now after the player was stopped and cleared and source set to null, it 
    // won't object to deleting the file
}

private void ME_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    ME.Stop();
    ME.Clear();
    ME.Source = null;
}

I hope that this helps.

于 2013-10-10T12:31:55.703 回答