#vb.net #multithreading
#vb.net #многопоточность
Вопрос:
Как старый программист систем мэйнфреймов, я вообще не специализируюсь ни на OO-мышлении, ни на Visual Basic. Мы с бывшим коллегой написали программу на VB (с именем FotoDB) для управления и представления наших семейных и праздничных фотографий. У нас есть своего рода база данных с описаниями и координатами GPS для всех из них.
FotoDB также может работать в «режиме презентации», а затем я хотел бы также показать OpenStreetMap области, где была сделана активная фотография. Я уже узнал, как использовать Leaflet.js для отображения карты в объекте WebBrowser.
Первая проблема, с которой я столкнулся, когда попытался использовать объект WebBrowser, заключалась в том, что я получил:
невозможно создать экземпляр, поскольку текущий поток не находится в однопоточной квартире.
Наша программа FotoDB должна оставаться многопоточной (я думаю): для некоторых вещей она использует BackgroundWorker, а также прослушивает 2 управляющих файла, которые могут быть изменены блокнотом (или аналогично).
Итак, я отказался от идеи добавления карты в виде небольшого элемента на главном экране FotoDB, но использую другую форму для объекта WebBrowser, и я запускаю ее в новом потоке STA-mode:
mapThread = New Thread(AddressOf form4MapShow)
mapThread.SetApartmentState(ApartmentState.STA)
mapThread.Start()
End Sub
Private Sub form4MapShow()
Form4map.Show()
End Sub
Это работает нормально, я могу отобразить раздел OpenStreetMap в моем «Form4map».
У меня все еще есть 2 проблемы (вероятно, сводимые к 1 проблеме)
- Мне нужно передать координаты GPS из основной программы в поток, в котором выполняется From4map
- Когда конечный пользователь выбирает новую фотографию для просмотра, основная программа должна передать новые координаты в Form4map
Я немного читал о делегировании, но не понимал его полностью. Я нашел примеры обновления ListView из другого потока и попытался имитировать его (когда новая фотография отображается в главном кадре, отправьте ее координаты GPS в текстовое поле Form4map), поэтому я закодировал (в качестве базового теста):
NieuweFoto(Form4map.txtNwFoto, "Nieuw " amp; Now.ToLocalTime)
End Sub
Public Delegate Sub newPhotoInvoker(ByVal txt As TextBox, ByVal itemtext As String)
Public Sub NieuweFoto(ByVal txt As TextBox, ByVal gpsInfo As String)
If Form4map.txtNwFoto.InvokeRequired Then
Form4map.txtNwFoto.Invoke(New newPhotoInvoker(AddressOf NieuweFoto), txt, gpsInfo)
Else
txt.Text = gpsInfo
End If
End Sub
Но теперь я получаю ту же ошибку, что и в начале:
Произошла ошибка при создании формы. См. Исключение.InnerException для получения подробной информации.
Ошибка: элемент управления ActiveX ‘8856f961-340a-11d0-a96b-00c04fd705a2’ не может быть создан, поскольку текущий поток не находится в однопоточной квартире.
Итак, я застрял. Есть ли простое решение?
Комментарии:
1. Вы не должны создавать новые потоки для отображения формы. Оставьте все материалы, связанные с графическим интерфейсом, в основном потоке пользовательского интерфейса по умолчанию и переместите любую работу в другой поток. Я бы еще раз повторил ту первую ошибку, которую вы получили и которая была связана с Webbrower. Опишите, как вы пришли к этой ошибке в первую очередь…
2. Странно… для моих тестов с объектом WebBrowser я использовал простой тестовый VB appl, который я использую для различных других небольших тестов. Я добавил новую простую форму с объектом WebBrowser, текстовым полем и кнопками формата a2. Когда я попытался запустить SHOW(), я получил сообщение об ошибке «не в однопоточной квартире». Итак, затем я начал использовать другой поток для этой формы. Теперь я использовал совершенно новое приложение VB, и я могу показать объект WebBrowser без каких-либо проблем. Я проведу тест с помощью веб-браузера my FotoDB и посмотрю, как это получится.
3. С объектом WebBrowser в основной форме моего приложения FotoDB больше не запускается. он сохраняется в InitializeComponent() в частном m_SyncContext как System. Многопоточность. SynchronizationContext Public Sub New() InitializeComponent() ‘ Этот вызов требуется разработчику. ‘ Добавьте любую инициализацию после вызова InitializeComponent() . Me.m_SyncContext = System. Многопоточность. SynchronizationContext.Current End Sub Я отметил, что это было необходимо, чтобы заставить FileSystemWatcher работать с потоком пользовательского интерфейса
4. Не уверен, в чем заключалась ваша проблема с FileSystemWatcher. Есть и другие способы «заставить его работать с потоком пользовательского интерфейса». Все, что вы изменили, чтобы заставить FSW работать, сломало другие части вашего приложения.
5. Ну, когда я добавляю веб-браузер в FotoDB в новой форме, это работает. Итак, я спасен, хотя я не знаю, почему это не удалось в моей тестовой программе.