"The calling thread cannot access this object because a different thread owns it" 使用 System.Windows.Media.MediaPlayer
"The calling thread cannot access this object because a different thread owns it" using System.Windows.Media.MediaPlayer
我在使用 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();
}
}
}
}
}
在与 UI 线程不同的线程中使用 WPF 元素时,如果需要同步调用,则需要使用 Dispatcher.Invoke 调用,但如果可以,最好使用 Dispatcher.BeginInvoke.
更改您的代码:
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
m_SoundPlayer.Stop();
m_SoundPlayer.Open(new Uri(szPath, UriKind.Relative));
m_SoundPlayer.Play();
}));
在 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
语句中。
非常感谢您的意见,这就是我想出的结果并且有效
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();
}
我在使用 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();
}
}
}
}
}
在与 UI 线程不同的线程中使用 WPF 元素时,如果需要同步调用,则需要使用 Dispatcher.Invoke 调用,但如果可以,最好使用 Dispatcher.BeginInvoke.
更改您的代码:
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
m_SoundPlayer.Stop();
m_SoundPlayer.Open(new Uri(szPath, UriKind.Relative));
m_SoundPlayer.Play();
}));
在 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
语句中。
非常感谢您的意见,这就是我想出的结果并且有效
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();
}