wpf 强制 MediaElement 在播放后释放流
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19294258/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Forcing MediaElement to Release Stream after playback
提问by Jap
I am creating an audio recorder control, with playback functionality.
我正在创建一个具有播放功能的录音机控件。
I use the media element to play the recorded audio like this:
我使用媒体元素像这样播放录制的音频:
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);
}
}
The problem i am facing is that when I use media element to play the recorded audio. The Stream is locked to the media element. I cannot overwrite the file or even play it again as the SetSource()method throws an exception.
我面临的问题是,当我使用媒体元素播放录制的音频时。Stream 被锁定到媒体元素。我无法覆盖文件,甚至无法再次播放,因为该SetSource()方法会引发异常。
Is there a way to force the media element to release the stream?
有没有办法强制媒体元素释放流?
回答by Jap
Based on @Sheridan answer this it what I came up with that works.
根据@Sheridan 的回答,这是我想出的有效方法。
Whenever MediaElementis stopped using Stop()function set the SourceProperty to nulllike this:
每当MediaElement停止使用Stop()函数时,将Source属性设置为null如下所示:
ResetMediaElement()
{
mediaElement.Stop();
mediaElement.Source = null;
}
This will close the stream attached to the media element, so that the related resource can be used somewhere else.
这将关闭附加到媒体元素的流,以便相关资源可以在其他地方使用。
回答by George Birbilis
If you use MediaElement, make sure you don't get bitten by this one: http://msdn.microsoft.com/en-us/library/cc626563(v=vs.95).aspx
如果您使用 MediaElement,请确保您不会被此咬伤:http: //msdn.microsoft.com/en-us/library/cc626563(v=vs.95) .aspx
ArgumentNullException - The mediaStreamSource is null.
...After calling this method, MediaElement.Source returns null. If this is called and MediaElement.Source is set, the last operation wins.
If a MediaElement is removed from the UI tree while is has an opened MediaStreamSource, subsequent calls to SetSource may be ignored. To ensure featureSetSource calls will work, set the Source property to null before detaching the MediaElement from the UI tree.
ArgumentNullException - mediaStreamSource 为 null。
...调用此方法后,MediaElement.Source 返回null。如果调用它并设置 MediaElement.Source,则最后一个操作获胜。
如果 MediaElement 从 UI 树中删除,同时具有打开的 MediaStreamSource,则可能会忽略对 SetSource 的后续调用。为确保 featureSetSource 调用有效,请在从 UI 树分离 MediaElement 之前将 Source 属性设置为 null。
naturally one would expect, if they only use SetSource(somestream) to use SetSource(null) to release the resources. Nope, they thought "better", you have to use Source=null instead to release resources and SetSource(null) throws ArgumentNullException
人们自然会期望,如果他们只使用 SetSource(somestream) 来使用 SetSource(null) 来释放资源。不,他们认为“更好”,你必须使用 Source=null 来释放资源,而 SetSource(null) 会抛出 ArgumentNullException
that is what I call a design bug (breaks the rule of "least expected" behavior and causes bugs that bite you at runtime only [unless somebody has made a static analysis rule to catch such a thing - would need metadata of course that some argument can't be null, like in Code Contracts])
这就是我所说的设计错误(打破了“最不期望”行为的规则并导致仅在运行时咬你的错误 [除非有人制定了静态分析规则来捕捉这样的事情 - 当然需要元数据,一些参数不能为空,就像在代码合同中一样])
I managed to introduce this bug while refactoring some code in ClipFlair Studio's AudioRecorder control the other day :-(
前几天我在ClipFlair Studio的 AudioRecorder 控件中重构了一些代码时设法引入了这个错误:-(
Note that you can't use at MediaElement something like Source= stream to open a Stream, since that is a Uri property (not an Object property to also accept Stream) and you have to use SetSource(stream) instead, so you'd also expect to be able to use SetSource(null) to release the resources.
请注意,您不能在 MediaElement 上使用Source= stream 之类的东西来打开 Stream,因为这是一个 Uri 属性(不是一个也接受 Stream 的 Object 属性),而您必须改用SetSource(流),所以您还期望能够使用 SetSource(null) 来释放资源。
Update: Fixedthis in AudioRecorderView class (uses MVVM pattern) of AudioRecorderControl, at Audio property's "set" accessor it needed the following null-guarding pattern:
更新:在 AudioRecorderControl 的 AudioRecorderView 类(使用 MVVM 模式)中修复了这个问题,在 Audio 属性的“设置”访问器中,它需要以下空值保护模式:
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;
回答by reza.cse08
mediaElement.Stop();
mediaElement.ClearValue(MediaElement.SourceProperty);
回答by Sheridan
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.CacheOptionproperty to BitmapCacheOption.OnLoad:
我在显示图像时遇到了类似的问题。在带有图像的控件中,每当用户尝试更新图像时,我都会收到“文件正在使用”错误。解决方案是将BitmapImage.CacheOption属性设置为BitmapCacheOption.OnLoad:
MSDNsays 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.
MSDN说如果您希望关闭用于创建 BitmapImage 的流,请将 CacheOption 设置为 BitmapCacheOption.OnLoad。默认的 OnDemand 缓存选项保留对流的访问权,直到需要图像为止,并且垃圾收集器处理清理。
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 mediaelementpost from MSDN, there isa (long winded) way to achieve this... from the relevant answer:
在搜索可用于您的类似属性后,MediaElement结果是没有。然而,根据对答案chacheoption为的MediaElement从MSDN后,有是一个(长篇大论)的方式来实现这一目标?从相关答案:
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.
我不确定您的 MediaElement 是否在 UserControl 中。但无论如何,您都可以将 UserControl 或 Control 设置为 IsEnabled=false,这反过来会触发事件处理程序 IsEnabledChanged。在其中放置必要的代码以停止播放 ME.Stop() 的 MediaElement,然后调用 ME.Clear() 和 ME.Source = null。之后,您应该发现删除源文件没有问题。
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.
我希望这个对你有用。

