PowerShell绑定按钮播放音乐时自动停止的问题求助
问题分析与解决方案
我之前也碰到过一模一样的问题!这个故障的核心原因是PowerShell 5.x的垃圾回收(GC)行为和PowerShell 2.0存在差异:
当你在按钮的Add_Click脚本块里创建$PlaySound变量时,这个变量属于脚本块的局部变量——脚本块执行完毕后,PowerShell的GC会判定这个对象没有任何外部引用,直接将其回收,导致音乐播放中途中断;而当你操作GUI(比如移动鼠标、调整窗口)时,会触发UI线程的GC检查,加速回收过程,所以播放会立刻停止。
而PowerShell 2.0的GC行为或变量作用域处理更宽松,局部变量不会被这么快回收;单独执行播放代码时,$PlaySound是全局作用域的变量,存在持久引用,所以能正常播放到结束。
解决方案1:将MediaPlayer对象放到全局作用域
把脚本块里的$PlaySound改成全局变量,让它在脚本块执行完后依然被引用,避免被GC回收:
Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing Add-Type -AssemblyName presentationcore # Build Form $Form = New-Object System.Windows.Forms.Form $Form.Text = "My Form" $Form.Size = New-Object System.Drawing.Size(200,200) $Form.StartPosition = "CenterScreen" $Form.Topmost = $True # Add Button $Button = New-Object System.Windows.Forms.Button $Button.Location = New-Object System.Drawing.Size(35,35) $Button.Size = New-Object System.Drawing.Size(120,23) $Button.Text = "Play music" $Form.Controls.Add($Button) # 修改Button事件:使用全局变量 $Button.Add_Click({ $location = 'D:\test\test.mp3' # 用global:前缀将对象放到全局作用域 $global:PlaySound = New-Object System.Windows.Media.MediaPlayer $global:PlaySound.open($location) $global:PlaySound.Play() }) #Show the Form $form.ShowDialog()| Out-Null
解决方案2:将MediaPlayer对象绑定到Form/Button的属性上
另一种更优雅的方式是把MediaPlayer对象绑定到Form或者Button的自定义属性上,让UI控件持有对象的引用,同样能避免GC回收:
Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing Add-Type -AssemblyName presentationcore # Build Form $Form = New-Object System.Windows.Forms.Form $Form.Text = "My Form" $Form.Size = New-Object System.Drawing.Size(200,200) $Form.StartPosition = "CenterScreen" $Form.Topmost = $True # 给Form添加一个自定义属性来存放MediaPlayer对象 $Form | Add-Member -MemberType NoteProperty -Name "AudioPlayer" -Value $null # Add Button $Button = New-Object System.Windows.Forms.Button $Button.Location = New-Object System.Drawing.Size(35,35) $Button.Size = New-Object System.Drawing.Size(120,23) $Button.Text = "Play music" $Form.Controls.Add($Button) # 修改Button事件:将对象绑定到Form的属性 $Button.Add_Click({ $location = 'D:\test\test.mp3' # 把MediaPlayer赋值给Form的自定义属性 $this.Parent.AudioPlayer = New-Object System.Windows.Media.MediaPlayer $this.Parent.AudioPlayer.open($location) $this.Parent.AudioPlayer.Play() }) #Show the Form $form.ShowDialog()| Out-Null
额外说明
如果需要播放多个音频或者控制播放状态(暂停、停止),建议维护一个全局的播放器对象,而不是每次点击都创建新的——这样既能避免GC问题,也能更好地管理音频播放生命周期。
内容的提问来源于stack exchange,提问作者DeadZed




