Как решить «InvalidCastException» в C #? - PullRequest
0 голосов
/ 05 января 2019

Я получаю ошибку во время выполнения, которая говорит мне, что он не может привести объект типа 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, включая конструктор, чтобы показать, что происходит каждый раз при создании 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

Редактировать: Вы можете просмотреть ошибку здесь .

Любая помощь приветствуется, спасибо.

Ответы [ 5 ]

0 голосов
/ 06 января 2019

Есть много способов исправить вашу проблему, но давайте просто сделаем пошаговое руководство вашего кода, чтобы вы могли увидеть, насколько это неуклюже. Проще говоря, вы делаете это:

Кнопка мыши нажата на элементе управления. Какой контроль? Ну и контроль в sender. Вы просматриваете все элементы управления в panel2, чтобы увидеть, является ли один из них sender, и затем вы выполняете некоторую работу.

Но почему бы вам перебрать все элементы управления в panel2? Когда вы создали элемент управления MusicNote, вы создали этот обработчик событий специально для этого элемента управления, чтобы информировать вас, когда на него нажата мышь. И теперь элемент управления вызывает событие и говорит: «Эй, кнопка мыши нажата, а она нажата на мне!» Видите ли, хотя panel2.Controls.OfType<MusicNote>() исправит вашу проблему, но зачем вам это делать? Это похоже на проблему XY .

Единственная причина, по которой вы будете делать то, что делаете, - это если вы создали элемент управления, подписались на событие 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;
    }
}
0 голосов
/ 05 января 2019

Когда ваша программа получает управление в обработчике событий, таком как Note_MouseDown, вы получаете ссылку на элемент управления, который «принял» событие в пользовательском интерфейсе (object sender).

Попробуйте привести sender к MusicNote, используя предложение as. Если приведение невозможно (поскольку sender отличается от MusicNote), использование предложения as не вызывает исключение - вместо этого он просто передает вам пустую ссылку, которую вы можете проверить.

Попробуйте что-то вроде этого:

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.

0 голосов
/ 05 января 2019

Чтобы зациклить только MusicNote экземпляров, вы можете использовать метод расширения OfType из LINQ:

foreach (MusicNote mn in panel2.Controls.OfType<MusicNote>()) {
   // do stuff
} 
0 голосов
/ 05 января 2019

Эта ошибка возникает каждый раз, когда цикл 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
                }
            }
0 голосов
/ 05 января 2019

Эта ошибка возникает, когда panel2.Controls содержит Controls не только типа MusicNote или PictureBox. Из ваших данных не ясно, какой тип всех panel2.Controls, должен быть только Collection или List PictureBoxes. Если panel2.Controls содержит какой-либо Control типа, отличного от Picturebox или MusicNote (например, TextBox и т. Д.), Вы получите ошибку. Если все типы panel2.Controls правильные, то, скорее всего, panel2 загружается не полностью при возникновении ошибки. Вы можете попробовать:

foreach (var mn in panel2.Controls)
if (sender == (MusicNote)mn)
...