alidayan Ответов: 3

System.invalidoperationexception: "коллекция была изменена; операция перечисления может не выполняться".


Всем привет,

Я пытаюсь разработать приложение, которое связывается с устройством HID, которое я получил в системе.InvalidOperationException: 'коллекция была изменена; операция перечисления может не выполняться.' ошибка.

Что я уже пробовал:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CyUSB;
using System.Threading;

namespace EGI
{
    public partial class EGI_Main : Form
    {
        // *********************** START OF PROGRAM MAIN ****************************** //

        USBDeviceList usbDevices = null;            // Pointer to list of USB devices
        CyHidDevice myHidDevice = null;             // Handle of USB device

        int VID = 0x04B4;                           // Cypress Vendor ID
        int PID = 0xE177;                           // Example Project Product ID

        bool communicate = false;                   // Communication status

        byte que = 00;                              // Command Byte
        byte PGAValue = 02;                         // PGA
        byte[] receivedDatas = new byte[128];       // Byte array to store 128 bytes of received data from device

        /**********************************************************************
        * NAME: EGI - Ekin Generic HID Communication Interface
        *
        * DESCRIPTION: Main function called initially upon the starting of the
        * application. Used to un-initialized variables, the GUI application, register
        * the event handlers, and check for a connected device.
        *
        ***********************************************************************/

        public EGI_Main()
        {
            CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
            // Create a list of CYUSB devices for this application
            usbDevices = new USBDeviceList(CyConst.DEVICES_HID);
            //Add event handlers for device attachment and device removal
            usbDevices.DeviceAttached += new EventHandler(usbDevices_DeviceAttached);
            usbDevices.DeviceRemoved += new EventHandler(usbDevices_DeviceRemoved);
            //Connect to the USB device
            GetDevice();
        }

        /**********************************************************************
        * NAME: EGI_Main_Load
        *
        * DESCRIPTION: Loads and sets necessary companents and settings on start.
        *
        ***********************************************************************/

        private void EGI_Main_Load(object sender, EventArgs e)
        {
            // Real data graph settings
            chartResult.ChartAreas[0].AxisX.ScaleView.Zoom(0, 127);
            chartResult.ChartAreas[0].AxisY.ScaleView.Zoom(0, 255);
            chartResult.Series[0].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            chartResult.Series[0].Color = Color.Black;
            chartResult.Series[0].BorderWidth = 3;

            // On line average result graph settings
            chartResult.Series.Add("onLineAvg");
            chartResult.Series["onLineAvg"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            chartResult.Series["onLineAvg"].Color = Color.Red;
            chartResult.Series["onLineAvg"].BorderWidth = 3;

            // Multipline with on line average result graph settings
            chartResult.Series.Add("multOnLineAvg");
            chartResult.Series["multOnLineAvg"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            chartResult.Series["multOnLineAvg"].Color = Color.Navy;
            chartResult.Series["multOnLineAvg"].BorderWidth = 3;

            // Exceed point(s) graph settings
            chartResult.Series.Add("exceed");
            chartResult.Series["exceed"].Color = Color.Brown;
            chartResult.Series["exceed"].BorderWidth = 3;

            for(int i = 0; i < 128; i++)
            {
                chartResult.Series[0].Points.AddXY(i, 0);
                chartResult.Series["onLineAvg"].Points.AddXY(i, 0);
                chartResult.Series["multOnLineAvg"].Points.AddXY(i, 0);
            }
        }

        /**********************************************************************
        * NAME: usbDevices_DeviceRemoved
        *
        * DESCRIPTION: Event handler for the removal of a USB device. When the removal
        * of a USB device is detected, this function will be called which will check to
        * see if the device removed was the device we were using. If so, then reset
        * device handler (myHidDevice), disable the timer, and update the GUI.
        *
        ***********************************************************************/

        public void usbDevices_DeviceRemoved(object sender, EventArgs e)
        {
            USBEventArgs usbEvent = e as USBEventArgs;
            if ((usbEvent.ProductID == PID) && (usbEvent.VendorID == VID))
            {
                InputTimer.Enabled = false; // Disable interrupts for polling HID
                myHidDevice = null;
                GetDevice(); // Process device status
            }
        }

        /**********************************************************************
        * NAME: usbDevices_DeviceAttached
        *
        * DESCRIPTION: Event handler for the attachment of a USB device. The function
        * first checks to see if a matching device is already connected by seeing
        * if the handler (myHidDevice) is null. If no device is previously attached,
        * the function will call GetDevice to check and see if a matching device was
        * attached.
        *
        ***********************************************************************/

        public void usbDevices_DeviceAttached(object sender, EventArgs e)
        {
            if (myHidDevice == null)
            {
                GetDevice(); // Process device status
            }
        }

        /**********************************************************************
        * NAME: GetDevice
        *
        * DESCRIPTION: Function checks to see if a matching USB device is attached
        * based on the VID and PID provided in the application. When a device is
        * found, it is assigned a handler (myHidDevice) and the GUI is updated to
        * reflect the connection. Additionally, if the device is not connected,
        * the function will update the GUI to reflect the disconnection.
        *
        ***********************************************************************/
        public void GetDevice()
        {
            //Look for device matching VID/PID
            myHidDevice = usbDevices[VID, PID] as CyHidDevice;
            if (myHidDevice != null) //Check to see if device is already connected
            {
                Status.Text = "Connected";
                Status.ForeColor = Color.Green;
                InputTimer.Enabled = true; //Enable background timer
            }
            else
            {
                Status.Text = "Disconnected";
                Status.ForeColor = Color.Red;
            }
        }
        
        /**********************************************************************
        * NAME: Set_VidPid_Click
        *
        * DESCRIPTION: Updates the applications Vendor ID and Product ID based on
        * user input when the "Set" button is clicked. This will cause the default VID
        * and PID of 0x04B4 and 0xE177 to be overwritten. The function will then
        * call GetDevice() to check for matching USB device.
        *
        ***********************************************************************/
        private void Set_VidPid_Click(object sender, EventArgs e)
        {
            //Respond to update of VID and PID value by pressing the "Set" button
            VID = Convert.ToInt32(VidTextBox.Text, 16);
            PID = Convert.ToInt32(PidTextBox.Text, 16);
            GetDevice();
        }

        /**********************************************************************
        * NAME: receive_Click
        *
        * DESCRIPTION: Starts and stops communication with device.
        *
        ***********************************************************************/

        private void receive_Click(object sender, EventArgs e)
        {
            if (communicate)
            {
                communicate = false;
                receive.Text = "Communicate";
                receive.BackColor = Color.White;
                receive.ForeColor = Color.Black;
            }
            else
            {
                communicate = true;
                receive.Text = "Stop";
                receive.BackColor = Color.Red;
                receive.ForeColor = Color.White;
                que = 00;
                backgroundWorkerGetAndProcessData.RunWorkerAsync();
            }
        }

        /**********************************************************************
        * NAME: communicateNow
        *
        * DESCRIPTION:Sends commands to device.
        *
        ***********************************************************************/

        private void communicateNow()
        {
            if (communicate)
            {
                // Load data into Output Buffer
                myHidDevice.Outputs.DataBuf[0] = 00;                                    // Report ID
                myHidDevice.Outputs.DataBuf[1] = (byte)numericUpDownThreshold.Value;    // Threshold
                myHidDevice.Outputs.DataBuf[2] = (byte)numericUpDownPB.Value;           // PB
                myHidDevice.Outputs.DataBuf[3] = PGAValue;                              // PGA
                myHidDevice.Outputs.DataBuf[4] = 87;                                    // W/R
                myHidDevice.Outputs.DataBuf[5] = que;                                   // Command byte
                myHidDevice.Outputs.DataBuf[6] = 00;
                myHidDevice.Outputs.DataBuf[7] = 00;
                myHidDevice.Outputs.DataBuf[8] = 00;
                myHidDevice.Outputs.DataBuf[9] = 00;

                // Function call to send data to device
                myHidDevice.WriteOutput();
                // Function call to receive data from device
                myHidDevice.ReadInput();

                byte[] tempData = myHidDevice.Inputs.DataBuf;

                for (int i = 2; i < myHidDevice.Inputs.DataBuf.Length - 1; i++)
                {
                    if (que == 0)
                        receivedDatas[i - 2] = tempData[i];
                    else if (que == 1)
                        receivedDatas[32 + i - 2] = tempData[i];
                    else if (que == 2)
                        receivedDatas[64 + i - 2] = tempData[i];
                    else if (que == 3)
                        receivedDatas[96 + i - 2] = tempData[i];
                }

                if (que < 03)
                {
                    que++;
                    communicateNow();
                }
                else
                {
                    que = 00;
                }
            }
        }
        

        /**********************************************************************
        * NAME: dataProcess
        *
        * DESCRIPTION: Regroup the datas, writes them to specific textboxes and
        * calls calculateAndDrawGraph to calculate and draw graph.
        *
        ***********************************************************************/

        private void dataProcess()
        {
            byte[] realDatas = receivedDatas;
            bool highLightPower = false;
            bool lowLightPower = false;

            // Clear textboxes
            receivedData_00.Text = null;
            receivedData_01.Text = null;
            receivedData_02.Text = null;
            receivedData_03.Text = null;

            // Count datas to separate to textboxes
            int countOfDatas = 0;

            // Write all datas to specified textboxes
            for(int i = 0; i < realDatas.Length; i++)
            {
                if (countOfDatas < 32)
                    receivedData_00.AppendText(realDatas[i] + " - ");
                else if (countOfDatas < 64)
                    receivedData_01.AppendText(realDatas[i] + " - ");
                else if (countOfDatas < 96)
                    receivedData_02.AppendText(realDatas[i] + " - ");
                else if (countOfDatas < 128)
                    receivedData_03.AppendText(realDatas[i] + " - ");

                // Check whether light power is high or low.
                if (realDatas[i] >= 190)
                    highLightPower = true;
                else if (realDatas[i] <= 25)
                    lowLightPower = true;

                countOfDatas++;
            }

            if (highLightPower)
            {
                labelLightPower.BackColor = Color.Red;
                labelLightPower.ForeColor = Color.White;
                labelLightPower.Text = "Decrease";
            }
            else if (lowLightPower)
            {
                labelLightPower.BackColor = Color.Yellow;
                labelLightPower.ForeColor = Color.Black;
                labelLightPower.Text = "Increase";
            }
            else
            {
                labelLightPower.BackColor = Color.Green;
                labelLightPower.ForeColor = Color.White;
                labelLightPower.Text = "";
            }

        }

        /**********************************************************************
        * NAME: calculateAndDrawGraph
        *
        * DESCRIPTION: Calculates averages and draws their graphs. Recall 
        * communicateNow() to receive new datas.
        *
        ***********************************************************************/

        private void calculateAndDrawGraph()
        {
            byte[] realDatas = receivedDatas;
            byte[] onLineAvg = new byte[128];
            int[] multOnLineAvg = new int[128];
            /* some codes */

            Thread.Sleep(900);
        }

        /**********************************************************************
        * NAME: radioButton_CheckedChanged
        *
        * DESCRIPTION: Sets PGAValue.
        *
        ***********************************************************************/

        private void radioButton_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton1.Checked)
                PGAValue = 01;
            else if (radioButton2.Checked)
                PGAValue = 02;
            else if (radioButton4.Checked)
                PGAValue = 04;
            else if (radioButton8.Checked)
                PGAValue = 08;
        }

        /**********************************************************************
        * NAME: backgroundWorkerGetAndProcessData_DoWork
        *
        * DESCRIPTION: Starts background worker to get data and process them.
        *
        ***********************************************************************/

        private void backgroundWorkerGetAndProcessData_DoWork(object sender, DoWorkEventArgs e)
        {
            communicateNow();
            dataProcess();
            calculateAndDrawGraph();
        }

        /**********************************************************************
        * NAME: backgroundWorkerGetAndProcessData_RunWorkerCompleted
        *
        * DESCRIPTION: Recalls background worker to get data and process them.
        *
        ***********************************************************************/

        private void backgroundWorkerGetAndProcessData_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            backgroundWorkerGetAndProcessData.RunWorkerAsync();
        }
    }
}

Karthik_Mahalingam

какая линия?

alidayan

Причины проблемы, когда я добавляю эти строки

 
chartResult.Series[0].Points.AddXY(i, realDatas[i]);          chartResult.Series["onLineAvg"].Points.AddXY(i, onLineAvg[i]);chartResult.Series["multOnLineAvg"].Points.AddXY(i, multOnLineAvg[i]); 

3 Ответов

Рейтинг:
5

alidayan

Я просто удаляю свои функции и перемещаю их коды внутрь

backgroundWorkerGetAndProcessData_RunWorkerCompleted
функции. Теперь нет никаких проблем.


Рейтинг:
0

Maciej Los

Вы можете посмотреть здесь: Перечисление коллекций, которые изменяются в C# | Magnus Montin[^]

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

Еще один ресурс:
Как справиться с этой ошибкой: коллекция была изменена; операция перечисления может не выполняться.[^]
"Коллекция была изменена; операция перечисления может не выполняться". ошибка[^]


Рейтинг:
0

OriginalGriff

Как я уже сказал по вашему предыдущему вопросу: Программа застревает при чтении данных из HID C#[^]

Цитата:
Вот почему я сказал, что он нуждается в полной переработке: вы не можете получить доступ к элементам управления пользовательского интерфейса из любого потока, кроме потока пользовательского интерфейса, а стандартные элементы управления .NET не являются потокобезопасными. Вы не можете просто бросить весь код в другой поток и надеяться, что он работает, вам нужно подумать о том, что нужно сделать в каком потоке и как два потока должны взаимодействовать друг с другом и когда.


alidayan

Проблема в том, что я не мог понять, как делать резьбу. Я пытался, но столкнулся с той же проблемой.

OriginalGriff

Тогда вам нужно учиться - мы не можем сделать это за вас, и это то, что вам нужно знать, чтобы выполнить задачу. Это хорошая серия статей на эту тему:
https://www.codeproject.com/Articles/26148/Beginners-Guide-to-Threading-in-NET-Part-of-n

Есть чтение - это сложно, но довольно просто, когда вы получаете вашу голову вокруг него. Но вы должны понять этот материал, если вы собираетесь использовать его без множества проблем позже.

alidayan

Причина проблемы в функции calculateAndDrawGraph(); при попытке нарисовать график. --серия[0] работает другие нет