我在使用System.Windows.Media.MediaPlayer播放声音方面遇到问题,第一次它是如何工作的,这有点奇怪,但是第二次它会抛出一个带有调用线程消息的异常无法访问此对象,因为另一个线程拥有它。
这是我下面的代码,请特别查看m_BackgroundWorker_DoWork,它实际播放声音文件位置与最后存储位置不同的声音:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Collections;
using System.Timers;
using System.Media;
namespace RPGInventor
{
public partial class GameMapPanel : UserControl
{
protected Point m_Size;
protected bool m_bGrid;
protected CMap m_Map;
protected System.Timers.Timer m_Timer;
//protected SoundPlayer m_SoundPlayer;
protected System.Windows.Media.MediaPlayer m_SoundPlayer;
protected string m_szLastMedia;
protected bool m_bRepeatBGS;
public GameMapPanel()
{
InitializeComponent();
this.Width = 0;
this.Height = 0;
m_Size = new Point(0, 0);
m_Timer = new System.Timers.Timer(1000 / 60);
m_Timer.Elapsed += m_Timer_Elapsed;
//m_SoundPlayer = new SoundPlayer();
m_SoundPlayer = new System.Windows.Media.MediaPlayer();
m_szLastMedia = "";
}
void m_Timer_Elapsed(object sender, ElapsedEventArgs e)
{
Invalidate();
}
public void setupGrid(int nCols, int nRows)
{
this.Width = nCols * 32;
this.Height = nRows * 32;
m_Size = new Point(nCols, nRows);
m_Map.setGridSize(nCols, nRows);
GameDialog parent = (GameDialog)this.Parent;
parent.updateScrollBars();
}
public void setMap(CMap map)
{
this.m_Map = map;
MainForm mf = (MainForm)CUtil.findForm("RPG Inventor");
//m_BackgroundWorker.RunWorkerAsync();
m_BackgroundWorker_DoWork(null, null);
for (int i = 0; i < getMap().getEvents().Count; ++i)
{
CEvent cevent = (CEvent)getMap().getEvents()[i];
if (cevent.getType() == (int)CEvent.EventType.TRANSFER)
{
CTransferEvent transferEvent = (CTransferEvent)cevent;
if (CResources.getLoadedMap(transferEvent.getMapName()) == null)
{
CMap temp = new CMap("", 0, 0);
CMap Loadmap = temp.retrieve(mf.m_Database, transferEvent.getMapName());
CResources.addLoadedMap(Loadmap);
}
CLayer layer = (CLayer)getMap().getMapLayers()[1];
CTransferObject transferObj = new CTransferObject(transferEvent);
transferObj.setLocation(new Point(transferEvent.getGridLoc().X * 32,
transferEvent.getGridLoc().Y * 32));
layer.addObject(transferObj, 2);
}
if (cevent.getType() == (int)CEvent.EventType.DOOR)
{
CDoorEvent doorEvent = (CDoorEvent)cevent;
if (CResources.getLoadedMap(doorEvent.getMapName()) == null)
{
CMap temp = new CMap("", 0, 0);
CMap Loadmap = temp.retrieve(mf.m_Database, doorEvent.getMapName());
CResources.addLoadedMap(Loadmap);
}
CLayer layer = (CLayer)getMap().getMapLayers()[1];
CDoorObject doorObj = new CDoorObject(doorEvent);
int nH = doorObj.getHeight();
int nDiff = nH - 32;
int nY = (doorEvent.getGridLoc().Y * 32) - nDiff;
doorObj.setLocation(new Point(doorEvent.getGridLoc().X * 32, nY));
layer.addObject(doorObj, 2);
}
}
}
public CMap getMap()
{
return this.m_Map;
}
public void addCharacterSet(CCharacterSet charSet)
{
CSpriteObject spriteObj = new CSpriteObject();
spriteObj.loadImage(charSet.CharGraphic);
spriteObj.setAnimations(charSet.CharSize.Y, charSet.CharSize.X);
spriteObj.setCharSet(charSet);
spriteObj.setVisible(true);
//spriteObj.setListener(this);
for (int i=0; i<m_Map.getEvents().Count; ++i)
{
CEvent cevent = (CEvent) m_Map.getEvents()[i];
if (cevent.getType() == (int)CEvent.EventType.PLAYER_START)
{
int nSpaceY = 32; int nDifference = spriteObj.getHeight() - nSpaceY;
spriteObj.setLocation(new Point(cevent.getGridLoc().X * 32,
(cevent.getGridLoc().Y * 32) - nDifference));
}
}
CLayer layer = (CLayer)m_Map.getMapLayers()[1];
layer.addObject(spriteObj, 2);
}
public void addCharacterSet(CCharacterSet charSet, Point ptGrid, int nDir)
{
GameDialog gd = (GameDialog)this.Parent;
MainForm mf = (MainForm)gd.Owner;
CSpriteObject spriteObj = new CSpriteObject();
spriteObj.loadImage(charSet.CharGraphic);
spriteObj.setAnimations(charSet.CharSize.Y, charSet.CharSize.X);
spriteObj.setCharSet(charSet);
spriteObj.setVisible(true);
spriteObj.setLocation(new Point(ptGrid.X * 32, ptGrid.Y * 32));
spriteObj.setDirection(nDir);
spriteObj.setCurrentAnim(nDir);
//spriteObj.setListener(this);
CLayer layer = (CLayer)m_Map.getMapLayers()[1];
layer.addObject(spriteObj, 2);
}
public void Closed()
{
m_SoundPlayer.Stop();
m_SoundPlayer.Close();
}
private void GameMapPanel_Load(object sender, EventArgs e)
{
//this.Height = 0;
//this.Width = 0;
GameDialog holder = (GameDialog)this.Parent;
holder.updateScrollBars();
m_Timer.Start();
}
private void GameMapPanel_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
//create back buffer
Bitmap backBuffer = new Bitmap(Width, Height);
Graphics backG = Graphics.FromImage(backBuffer);
if (m_Map != null)
{
ArrayList mapLayers = m_Map.getMapLayers();
for (int i = 0; i < mapLayers.Count; ++i)
{
CLayer layer = (CLayer)mapLayers[i];
layer.DrawLayer(backG);
}
}
g.DrawImage(backBuffer, new Point(0, 0));
}
private void GameMapPanel_MouseEnter(object sender, EventArgs e)
{
this.Focus();
}
private void GameMapPanel_KeyDown(object sender, KeyEventArgs e)
{
//get CharSet
GameDialog gd = (GameDialog)this.Parent;
MainForm mf = (MainForm)gd.Owner;
CSpriteObject player = new CSpriteObject();
CCharacterSet dbCharSet = (CCharacterSet)mf.m_Database.m_Characters[0];
ArrayList list = m_Map.getMapLayers();
CLayer layer = (CLayer)list[1];
for (int i = 0; i < layer.getObjects().Count; i++)
{
CMapObject mapObj = layer.getObject(i);
if (mapObj.getType() == (int)CMapObject.MapObjectType.SPRITE)
{
CSpriteObject sprite = (CSpriteObject)mapObj;
if (sprite.getCharSet().Name.Equals(dbCharSet.Name))
{
player = sprite;
}
}
}
if (e.KeyCode == Keys.Down)
{
player.setDirection((int)CSpriteObject.Direction.DOWN);
player.startTimer();
}
if (e.KeyCode == Keys.Up)
{
player.setDirection((int)CSpriteObject.Direction.UP);
player.startTimer();
}
if (e.KeyCode == Keys.Left)
{
player.setDirection((int)CSpriteObject.Direction.LEFT);
player.startTimer();
}
if (e.KeyCode == Keys.Right)
{
player.setDirection((int)CSpriteObject.Direction.RIGHT);
player.startTimer();
}
}
private void GameMapPanel_KeyUp(object sender, KeyEventArgs e)
{
//get CharSet
GameDialog gd = (GameDialog)this.Parent;
MainForm mf = (MainForm)gd.Owner;
CSpriteObject player = new CSpriteObject();
CCharacterSet dbCharSet = (CCharacterSet)mf.m_Database.m_Characters[0];
ArrayList list = m_Map.getMapLayers();
CLayer layer = (CLayer)list[1];
for (int i = 0; i < layer.getObjects().Count; i++)
{
CMapObject mapObj = layer.getObject(i);
if (mapObj.getType() == (int)CMapObject.MapObjectType.SPRITE)
{
CSpriteObject sprite = (CSpriteObject)mapObj;
if (sprite.getCharSet().Name.Equals(dbCharSet.Name))
{
player = sprite;
}
}
}
if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right)
{
player.stopTimer();
}
}
private void GameMapPanel_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Down:
case Keys.Up:
case Keys.Left:
case Keys.Right:
e.IsInputKey = true;
break;
}
}
private void m_BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
MainForm mf = (MainForm)CUtil.findForm("RPG Inventor");
if (this.getMap().getSoundDir() != null && this.getMap().getSoundDir() != ""
&& this.getMap().getSoundName() != null && this.getMap().getSoundName() != "")
{
String szPath = ".\\Projects\\" + mf.m_Database.m_Name + "\\Audio\\" +
this.getMap().getSoundDir() + "\\" + this.getMap().getSoundName();
string szSoundPlayerPath = m_szLastMedia;
if (!szSoundPlayerPath.Equals(szPath))
{
try
{
m_SoundPlayer.Stop();
m_SoundPlayer.Open(new Uri(szPath, UriKind.Relative));
m_SoundPlayer.Play();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
//m_SoundPlayer.Stop();
//m_SoundPlayer.SoundLocation = szPath;
//m_SoundPlayer.PlayLooping();
}
}
}
}
}
答案 0 :(得分:0)
在WinForms中,无法从任何其他线程访问在一个线程中创建的控件。因此,您需要使用Invoke
在主线程上运行代码。
试试这个:
if (!szSoundPlayerPath.Equals(szPath))
{
try
{
this.Invoke((MethodInvoker)delegate
{
m_SoundPlayer.Stop();
m_SoundPlayer.Open(new Uri(szPath, UriKind.Relative));
m_SoundPlayer.Play();
});
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
我不能100%确定上述三行是否导致异常,但您只需要在Invoke
语句中包含导致错误的任何代码行。
答案 1 :(得分:0)
非常感谢您的投入,这就是我提出的结果,并且它可以正常工作
if (InvokeRequired)
{
this.BeginInvoke(new Action(() =>
{
m_SoundPlayer.Stop();
m_SoundPlayer.Open(new Uri(szPath, UriKind.Relative));
m_SoundPlayer.Play();
}));
}
else
{
m_SoundPlayer.Stop();
m_SoundPlayer.Open(new Uri(szPath, UriKind.Relative));
m_SoundPlayer.Play();
}
答案 2 :(得分:-2)
如果你想要一个同步调用,你需要使用Dispatcher.Invoke来调用与UI线程不同的线程内的WPF元素,但是如果可以,则优先使用Dispatcher.BeginInvoke。
使用以下代码更改您的代码:
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
m_SoundPlayer.Stop();
m_SoundPlayer.Open(new Uri(szPath, UriKind.Relative));
m_SoundPlayer.Play();
}));