如何在 C# 中解决 "InvalidCastException"?
How do I solve an "InvalidCastException" in C#?
我收到一个 运行-time 错误,它告诉我无法将 PictureBox 类型的对象转换为类型 MusicNote(MusicNote 继承自 PictureBox。)
private void Note_MouseDown(object sender, MouseEventArgs e)
{
//try
//{
foreach (MusicNote mn in panel2.Controls) //this is where the error occurs
{
if (sender == mn)
{
if (e.Button == MouseButtons.Right)
{
count = 0;
timer1.Start();
sp.SoundLocation = MusicNote_path + mn.note + ".wav";
sp.Play();
}
if (e.Button == MouseButtons.Left)
{
dragging = true;
mn.BackColor = Color.HotPink;
}
下面是 MusicNote class 的一部分,包括构造函数,以显示每次构造 MusicNote 时发生的情况:
class MusicNote : PictureBox
{
public int notepitch;
public int noteduration;
public String noteshape;
public String note;
enum Accid { sharp, flat, sole };
public static String NoteImage_path = Environment.CurrentDirectory + @"\Notes-Images\";
public static int xLoc = 30;
public int yLoc = 0;
System.Timers.Timer timer1 = new System.Timers.Timer();
public MusicNote(int iNotepitch, int iDuration, String iBnoteShape, String iNote)
{
notepitch = iNotepitch;
noteduration = iDuration;
noteshape = iBnoteShape;
note = iNote;
ImageLocation = NoteImage_path + noteshape + ".bmp";
BackColor = Color.Transparent;
ClientSize = new Size(35, 35);
//BringToFront();
Location = new Point(xLoc, getyLoc(iNote));
xLoc += 37;
}
面板的填充方式如下:
MusicNote mn = new MusicNote(mk.getMusicNote(), duration, bNoteShape, mk.getNote());
mn.MouseDown += new MouseEventHandler(Note_MouseDown);
mn.MouseUp += new MouseEventHandler(Note_MouseUp);
mn.MouseClick += new MouseEventHandler(Note_MouseClick);
panel2.Controls.Add(mn); //adding MusicNote component to MusicStaff (panel2) collection
编辑:可以查看错误here。
感谢任何帮助,谢谢。
当 panel2.Controls
不仅包含 MusicNote
或 PictureBox
类型的 Controls
时,会发生此错误。根据您的数据,不清楚所有 panel2.Controls
的类型是什么,应该只是 PictureBoxes 的 Collection
或 List
。如果 panel2.Controls
包含不同于 Picturebox
或 MusicNote
类型的任何 Control
(例如 TextBox
等),您将收到错误消息。如果所有 panel2.Controls
的类型都是正确的,那么很可能 panel2
在错误发生时没有完全加载。
你可以试试:
foreach (var mn in panel2.Controls)
if (sender == (MusicNote)mn)
要仅循环 MusicNote
个实例,您可以使用 LINQ 中的 OfType
扩展方法:
foreach (MusicNote mn in panel2.Controls.OfType<MusicNote>()) {
// do stuff
}
每次 foreach (MusicNote mn in panel2.Controls)
循环发现 MusicNote
.
之后的任何其他内容时,都会发生此错误
您可以通过循环所有 Controls
来避免这种情况,例如 foreach (Control cntrl in panel2.Controls)
示例代码:
foreach (Control cntrl in panel2.Controls)
{
if(cntrl is MusicNote)
{
//do something with the MusicNote Control
}
}
当您的程序在 Note_MouseDown
等事件处理程序中获得控制权时,您会收到对 'took' UI (object sender
) 事件的控件的引用。
尝试使用 as
子句将 sender
转换为 MusicNote
。如果无法转换(因为 sender
不是 MusicNote
),使用 as
子句不会抛出异常——相反它只会给你一个 NULL 引用,它你可以测试。
尝试这样的事情:
private void Note_MouseDown(object sender, MouseEventArgs e)
{
var mn = sender as MusicNote;
if (mn != null)
{
if (e.Button == MouseButtons.Right)
{
count = 0;
mn.timer1.Start();
sp.SoundLocation = MusicNote_path + mn.note + ".wav";
sp.Play();
}
if (e.Button == MouseButtons.Left)
{
dragging = true;
mn.BackColor = Color.HotPink;
}
}
}
你真的不需要foreach
。
有很多方法可以解决您的问题,但让我们先浏览一下您的代码,以便您了解它有多么笨拙。用简单的英语来说,你正在这样做:
The mouse button is pressed down on a control. Which control? Well the control in sender
. You loop through all the controls in panel2
to see if one of them is the sender
and then you do some work.
但是为什么要遍历 panel2
中的所有控件?当您创建 MusicNote
控件时,您专门为该控件创建了这个事件处理程序,以便在鼠标按下时通知您。现在控件正在引发一个事件并说 "Hey, the mouse button is down and it is down on me!" 你看,即使 panel2.Controls.OfType<MusicNote>()
会解决你的问题,但你为什么要这样做?好像是 XY problem.
你会做你正在做的事情的唯一原因是,如果你创建了控件,订阅了 MouseDown
事件,然后以编程方式将控件从一个面板移动到另一个面板,而你只想做一些工作如果当鼠标按下时控件恰好位于 panel2
中。我怀疑你把它搬来搬去;即使你这样做了,也有更好的方法来处理这种情况。
正解
你不需要循环,你只需要这个:
private void Note_MouseDown(object sender, MouseEventArgs e)
{
// If neither right nor left is down, return immediately because nothing needs
// to be done.
if (!(e.Button == MouseButtons.Right || e.Button == MouseButtons.Left))
{
return;
}
// This should not fail, if it does, then ask yourself why have you created
// this handler for things which are not MusicNote.
MusicNote mn = (MusicNote)sender;
// Do some work below
if (e.Button == MouseButtons.Right)
{
count = 0;
timer1.Start();
sp.SoundLocation = MusicNote_path + mn.note + ".wav";
sp.Play();
}
if (e.Button == MouseButtons.Left)
{
dragging = true;
mn.BackColor = Color.HotPink;
}
}
我收到一个 运行-time 错误,它告诉我无法将 PictureBox 类型的对象转换为类型 MusicNote(MusicNote 继承自 PictureBox。)
private void Note_MouseDown(object sender, MouseEventArgs e)
{
//try
//{
foreach (MusicNote mn in panel2.Controls) //this is where the error occurs
{
if (sender == mn)
{
if (e.Button == MouseButtons.Right)
{
count = 0;
timer1.Start();
sp.SoundLocation = MusicNote_path + mn.note + ".wav";
sp.Play();
}
if (e.Button == MouseButtons.Left)
{
dragging = true;
mn.BackColor = Color.HotPink;
}
下面是 MusicNote class 的一部分,包括构造函数,以显示每次构造 MusicNote 时发生的情况:
class MusicNote : PictureBox
{
public int notepitch;
public int noteduration;
public String noteshape;
public String note;
enum Accid { sharp, flat, sole };
public static String NoteImage_path = Environment.CurrentDirectory + @"\Notes-Images\";
public static int xLoc = 30;
public int yLoc = 0;
System.Timers.Timer timer1 = new System.Timers.Timer();
public MusicNote(int iNotepitch, int iDuration, String iBnoteShape, String iNote)
{
notepitch = iNotepitch;
noteduration = iDuration;
noteshape = iBnoteShape;
note = iNote;
ImageLocation = NoteImage_path + noteshape + ".bmp";
BackColor = Color.Transparent;
ClientSize = new Size(35, 35);
//BringToFront();
Location = new Point(xLoc, getyLoc(iNote));
xLoc += 37;
}
面板的填充方式如下:
MusicNote mn = new MusicNote(mk.getMusicNote(), duration, bNoteShape, mk.getNote());
mn.MouseDown += new MouseEventHandler(Note_MouseDown);
mn.MouseUp += new MouseEventHandler(Note_MouseUp);
mn.MouseClick += new MouseEventHandler(Note_MouseClick);
panel2.Controls.Add(mn); //adding MusicNote component to MusicStaff (panel2) collection
编辑:可以查看错误here。
感谢任何帮助,谢谢。
当 panel2.Controls
不仅包含 MusicNote
或 PictureBox
类型的 Controls
时,会发生此错误。根据您的数据,不清楚所有 panel2.Controls
的类型是什么,应该只是 PictureBoxes 的 Collection
或 List
。如果 panel2.Controls
包含不同于 Picturebox
或 MusicNote
类型的任何 Control
(例如 TextBox
等),您将收到错误消息。如果所有 panel2.Controls
的类型都是正确的,那么很可能 panel2
在错误发生时没有完全加载。
你可以试试:
foreach (var mn in panel2.Controls)
if (sender == (MusicNote)mn)
要仅循环 MusicNote
个实例,您可以使用 LINQ 中的 OfType
扩展方法:
foreach (MusicNote mn in panel2.Controls.OfType<MusicNote>()) {
// do stuff
}
每次 foreach (MusicNote mn in panel2.Controls)
循环发现 MusicNote
.
您可以通过循环所有 Controls
来避免这种情况,例如 foreach (Control cntrl in panel2.Controls)
示例代码:
foreach (Control cntrl in panel2.Controls)
{
if(cntrl is MusicNote)
{
//do something with the MusicNote Control
}
}
当您的程序在 Note_MouseDown
等事件处理程序中获得控制权时,您会收到对 'took' UI (object sender
) 事件的控件的引用。
尝试使用 as
子句将 sender
转换为 MusicNote
。如果无法转换(因为 sender
不是 MusicNote
),使用 as
子句不会抛出异常——相反它只会给你一个 NULL 引用,它你可以测试。
尝试这样的事情:
private void Note_MouseDown(object sender, MouseEventArgs e)
{
var mn = sender as MusicNote;
if (mn != null)
{
if (e.Button == MouseButtons.Right)
{
count = 0;
mn.timer1.Start();
sp.SoundLocation = MusicNote_path + mn.note + ".wav";
sp.Play();
}
if (e.Button == MouseButtons.Left)
{
dragging = true;
mn.BackColor = Color.HotPink;
}
}
}
你真的不需要foreach
。
有很多方法可以解决您的问题,但让我们先浏览一下您的代码,以便您了解它有多么笨拙。用简单的英语来说,你正在这样做:
The mouse button is pressed down on a control. Which control? Well the control in
sender
. You loop through all the controls inpanel2
to see if one of them is thesender
and then you do some work.
但是为什么要遍历 panel2
中的所有控件?当您创建 MusicNote
控件时,您专门为该控件创建了这个事件处理程序,以便在鼠标按下时通知您。现在控件正在引发一个事件并说 "Hey, the mouse button is down and it is down on me!" 你看,即使 panel2.Controls.OfType<MusicNote>()
会解决你的问题,但你为什么要这样做?好像是 XY problem.
你会做你正在做的事情的唯一原因是,如果你创建了控件,订阅了 MouseDown
事件,然后以编程方式将控件从一个面板移动到另一个面板,而你只想做一些工作如果当鼠标按下时控件恰好位于 panel2
中。我怀疑你把它搬来搬去;即使你这样做了,也有更好的方法来处理这种情况。
正解
你不需要循环,你只需要这个:
private void Note_MouseDown(object sender, MouseEventArgs e)
{
// If neither right nor left is down, return immediately because nothing needs
// to be done.
if (!(e.Button == MouseButtons.Right || e.Button == MouseButtons.Left))
{
return;
}
// This should not fail, if it does, then ask yourself why have you created
// this handler for things which are not MusicNote.
MusicNote mn = (MusicNote)sender;
// Do some work below
if (e.Button == MouseButtons.Right)
{
count = 0;
timer1.Start();
sp.SoundLocation = MusicNote_path + mn.note + ".wav";
sp.Play();
}
if (e.Button == MouseButtons.Left)
{
dragging = true;
mn.BackColor = Color.HotPink;
}
}