Индексатор, созданный для просмотра массива, не видит изменений, внесенных в массив

Я очень плохо знаком с C# и создаю класс последовательного порта для разработанной мной платы. В котором этот класс содержит методы для открытия / закрытия последовательного порта, подключенного к плате. Он также должен читать сообщения с доски и записывать сообщения от пользовательского интерфейса на доску (я использую приложение форм для ввода и отображения значений).

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

Для этого я создал индексатор, чтобы указать на массив (из формы) и взять байты, которые он желает.

    uint[] serialPortReceiveBuffer = new uint[3];
    public delegate void Del();
    Del promptFormAction = Form1.MsgReceived;

    public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {   
        for (int i = 0; i <= 2; i++) 
        {
            serialPortReceiveBuffer[i] = (uint)serialPort1.ReadByte();
        }

        promptFormAction();  
    }

    public uint this[uint i]
    {
        get { return serialPortReceiveBuffer[i]; }
    }

это код в моем классе pcbSerialPort, и код, связанный с ним в классе Form1, выглядит следующим образом:

    public static void MsgReceived()
    {
        Form1 _frm = new Form1();
        _frm.analyzeIncomingMessage();
    }

    public void analyzeIncomingMessage()
    {
        if (PCB[0] == 63)
        {
            setBoardDesignator(PCB[1], PCB[2]);
        }
    }

Моя проблема в том, что когда я использую индексатор для доступа к serialPortReceiveBuffer, он не видит изменений, которые я внес в него, помещая полученные байты в тот же массив. Например, когда я получаю строку моего собственного протокола -> "?10", буфер заполняется [63][49][48]

Хотя, когда я пытаюсь получить доступ к этому буферу с помощью индексатора, я получаю [0][0][0]

Пожалуйста, кто-нибудь может помочь? Кроме того, я знаю, что, возможно, есть еще несколько вещей, которые я мог бы сделать лучше, так что если бы у вас были общие советы, которые были бы хороши. Также на языке, который я могу понять. Я просто разбираюсь во многих аспектах C#, я занимался встраиваемым программным обеспечением в течение прошлого года, но я не считаю себя компетентным программистом.

Спасибо

2 ответа

Решение

Из вашего кода я не совсем уверен, что PCB объект, с которым вы работаете в вашей форме, на самом деле тот, который получает данные. Вполне возможно, что вы работаете с двумя разными экземплярами, особенно когда вы создаете новый экземпляр Form1 всякий раз, когда данные приходят!

(РЕДАКТИРОВАТЬ: Из вашего комментария к вопросу ясно, что это именно проблема. Следуйте этим инструкциям, чтобы получить то, что вы хотите).

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

Я бы объявил событие, на которое может подписаться экземпляр формы, передав данные для анализа в событие:

 public class MessageReceivedEventArgs: EventArgs
 {
     public MessageReceivedEventArgs(byte[] data) : base()
     {
         Data = data;
     }

     public byte[] Data
     {
         get;
         private set;
     }
}

public event EventHandler<MessageReceivedEventArgs> MessageReceived;

Тогда я бы изменил ваш DataReceivedсобытие следующим образом:

public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{   
    for (int i = 0; i <= 2; i++) 
    {
        serialPortReceiveBuffer[i] = (uint)serialPort1.ReadByte();
    }

    byte[] dataCopy = new byte[serialPortReceiveBuffer.Length];
    Array.Copy(serialPortReceiveBuffer, dataCopy, dataCopy.Length);

    promptFormAction(dataCopy);  
}

private void promptForAction(byte[] data)
{
    if (MessageReceived != null)
        MessageReceived(this, new MessageReceivedEventArgs(data));
}

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

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

Чтобы использовать это, Form1 должно выглядеть примерно так (примерно);

public class Form1
{
    pcbSerialPort PCB; // The name of that class I don't know from your code

    public Form1()
    {
        PCB = new pcbSerialPort();
        PCB.MessageReceived += MessageReceived;
    } 

    private void MessageReceived(object sender, pcbSerialPort.MessageReceivedEventArgs e)
    {
        analyzeIncomingMessage(e.Data);
    }

    private void analyzeIncomingMessage(byte[] data)
    {
        if (data[0] == 63)
        {
            setBoardDesignator(data[1], data[2]);
        }
    }
}

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

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

Я думаю, что ответ Торстена хороший, и было бы разумно изменить его в том же духе, но как абсолютный минимум, если вы хотите, чтобы он был таким, чтобы вы создали новый Form1 экземпляр для каждого полученного сообщения, тогда вам нужно будет передать экземпляр pcbSerialPort в MessageReceived а затем к конструктору вашего Form1 учебный класс. Что-то вроде:

Action<pcbSerialPort> promptFormAction = Form1.MsgReceived;

public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{   
    // as Thorsten noted, you need to rethink this loop anyway
    // what if there aren't at least three bytes to read?
    for (int i = 0; i <= 2; i++) 
    {
        serialPortReceiveBuffer[i] = (uint)serialPort1.ReadByte();
    }

    promptFormAction(this);  
}

И ваш статический метод:

public static void MsgReceived(pcbSerialPort pcb)
{
    Form1 _frm = new Form1(pcb);
    _frm.analyzeIncomingMessage();
}

А ты конструктор для Form1:

public Form1(pcbSerialPort pcb)
{
    PCB = pcb;
}
Другие вопросы по тегам