2015-11-24 2 views
-1

Я пытаюсь реорганизовать некоторый код из основной формы, где он работал отлично, в модуль, где он не работает.Замена Me.BeginInvoke() при рефакторинге на модуль

В рабочей версии вся информация, поступающая через последовательный порт, обрабатывается надлежащим образом. Тем/делегаты созданы здесь, что конец, когда они успешно преобразуют информацию в соответствии с гигантской PLM() функция ниже:

https://github.com/ocdtrekkie/HAController/blob/a8def5916686207b0ac4a0707c9406ad6ba39cfa/Form1.vb#L197

Когда я переехал все это в модуль, большая часть кода работает отлично , Мне удалось получить объект SerialPort, созданный и обработанный надлежащим образом в модуле. Я могу отправлять подключения к последовательному порту просто отлично и все, однако Me.BeginInvoke() не может быть использован в модуле. Я обнаружил, что вместо того, чтобы вместо этого обрабатывать обработчик(), он создает один поток, и он будет обрабатывать одну команду, но обычная потоковая обработка больше не происходит. Так что обработчик() не был правильным выбором того, что я должен здесь положить.

https://github.com/ocdtrekkie/HAController/blob/9504237b2a220f1eaf946bff0c86906a2ad5fb43/modInsteon.vb#L181

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

Редактировать: Давайте посмотрим, смогу ли я предоставить лучшую информацию. (Удивительно, что я могу наберешь downvote перед любым Ответчик понимает, что мне нужно или не нужно!)

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

объяснение оригинального автора о том, что он делает, может быть более полезным, чем мое собственное понимание: http://www.madreporite.com/insteon/receiving.html

В Visual Basic 2005 (это также относится и к 2008 году), объект SerialPort присваивается свой собственный поток и работает параллельно с остальной частью вашего приложения. В принципе это означает, что он может идти в ногу с последовательным устройством, независимо от того, с чем связана основная программа. Тем не менее, объекты и подпрограммы в одном потоке сильно ограничены в их способности взаимодействовать с объектами и подпрограммами в других потоках, а это значит, что, хотя есть событие SerialPort_Datareceived, вы очень ограничены тем, что вы можете сделать в нем. Даже если вы записываете последовательные данные в глобальную переменную, если вы также меняете эту переменную из другого потока, данные могут легко потеряться, поскольку они мешают друг другу.

В результате я создал массив байтов. Событие SerialPort_Datareceived записывает байты в массив и обновляет указатель, чтобы указать добавленный последний байт. Затем событие будет вызывать подпрограмму делегата в основном потоке (что в основном означает попросить другой поток выполнить эту подпрограмму, по своему усмотрению, без параметров), которые в конечном итоге будут выполняться. Подпрограмма в другом потоке наблюдает (но никогда не меняет) указатель и массив, чтобы увидеть, какие данные вошли, используя собственный указатель для запоминания последнего байта, который он обработал. Указатель и массив могут меняться во время выполнения этой другой подпрограммы.

Поскольку я не действительно возвращая любую информацию пользовательского интерфейса, я не думаю, что это обязательно должно быть «UI нить» с ней.

Edit2: Если PLM() функция уже предназначена для правильной работы, даже если есть несколько экземпляров, работающих одновременно, и я особенно не нужно синхронизировать поток пользовательского интерфейса, может я просто огонь от каждого экземпляра в новом потоке, используя System.Threading.Thread как-то вместо этого?

+0

Для вызова функции BeginInvoke() требуется ссылка на объект Form или Control. Поэтому вам нужна другая переменная в вашем модуле. В общем, вы должны, по крайней мере, иметь один из «главного» окна, которое всегда вокруг. Назначьте переменную модуля в своем конструкторе. Если смерть и отчаяние звонят по телефону, тогда Application.OpenForms (0) может это сделать. –

+0

Код на самом деле ничего не возвращает в пользовательский интерфейс, в настоящее время все, что он делает, на самом деле является WriteEntry в журнале событий. Надеюсь, я смогу получить функциональность этого, не передав форму как-нибудь. – ocdtrekkie

ответ

0

После прочтения немного больше в том, как оригинальный автор написал код, а также тот факт, что он должен (относительно) безопасно работать с несколькими вызовами из PLM(), запущенного одновременно, я попытался заменить всю функцию «Делегат» на Threading.Thread.

Следующая совершить, кажется, работает: https://github.com/ocdtrekkie/HAController/commit/9d9aeecce74ab40602863c6dc878ff09c89565af

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

0

Конечно, Me.BeginInvoke не может быть использован в модуле. Me не могут быть использованы в модуле. Всякий раз, когда вы используете Me, вы ссылаетесь на текущий экземпляр текущего типа. У модулей нет экземпляров, поэтому Me не имеет смысла.

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

Имейте в виду, что экземпляры формы по умолчанию имеют отношение к потоку, поэтому, если вы используете экземпляр по умолчанию в своем модуле, вы не можете вызвать BeginInvoke, потому что он будет в неправильном экземпляре.

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

+0

Я знаю, что я не могу использоваться в модуле, сообщение об ошибке в VS довольно ясно. ;) Мне нужно знать, как реплицировать существующую функциональность этого кода, которая больше не возвращает ничего в поток пользовательского интерфейса. – ocdtrekkie

+0

«Мне нужно знать, как копировать существующие функции этого кода ...». И я рассказал вам, как это сделать. – jmcilhinney

+0

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

2

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

Глядя на ваш код можно реорганизовать, как с помощью окончания:

Sub Load(synchronizationTarget As ISynchronizeInvoke) 
    SerialPLM = New System.IO.Ports.SerialPort 
    AddHandler SerialPLM.DataReceived, Sub(s, e) DataReceived(synchronizationTarget) 
End Sub 


Private Sub DataReceived(synchronizationTarget As ISynchronizeInvoke) 
    ' omitted 

    ' invoke delegate 
    Dim handler As New mySerialDelegate(AddressOf PLM) 
    synchronizationTarget.BeginInvoke(handler, Nothing) 
End Sub 

' and use in your form like: 
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    modInsteon.Load(Me) 
End Sub 
+0

Метод PLM - это не мой код. Я уже давно укоротил его. Работа в процессе! Я не уверен, что мне нужна привязка к потоку пользовательского интерфейса конкретно или нет, этот метод больше не возвращает никаких данных в пользовательский интерфейс. В конце концов, я хочу полностью исключить UI из уравнения и перестроить его как сервисное или консольное приложение. – ocdtrekkie

Смежные вопросы