Вопрос: Обновление интерфейса из другого потока | Добавлено: 22.02.08 07:45 |
Автор вопроса: ![]() |
Доброго времени суток! У меня возникла проблема: Приложение занимается копированием файлов. И делает это в другом потоке. Вопрос: Как из Второго потока(через делегаты, события или "заклинания" обновлять содержимое ProgressBar'a и Label'ов?
Я создал отдельный класс, через который передал другому потоку параметры для его запуска (список файлов для копирования и т.д.). В классе создал события, которые возникают при завершении копирования каждого файла, и эти события работают!... но в другом потоке. Как мне обновлять ПрогрессБар по завершении копирования файла??? Или как мне инициализировать событие из кода второго процесса, а обработчик создать в основном? Заранее спасибо! |
Ответы | Всего ответов: 19 |
Номер ответа: 1 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ICQ: 318170731 Вопросов: 15 Ответов: 96 |
Профиль | Цитата | #1 | Добавлено: 22.02.08 10:38 |
Изменить свойства элементов можно только в методе потока, в котором этот элемент был создан! что бы вызвать этот метод, надо использовать делегаты.
‘делегат Private Delegate Sub DelegateChangeProperty ‘поток из которого надо изменить свойства Private Sub Thread_1 Dim myDelegate As New SetClipboardText(AddressOf ChangeProperty) ‘Вызов метода в основном потоке myDelegate.Invoke() End sub ‘Метод в основном потоке Privet Sub ChangeProperty ‘Меняем свойства элементов End sub |
Номер ответа: 2 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ICQ: 318170731 Вопросов: 15 Ответов: 96 |
Профиль | Цитата | #2 | Добавлено: 22.02.08 10:40 |
P.S. - передачу параметров никто не отменял |
Номер ответа: 3 Автор ответа: ![]() ![]() ![]() ![]() Вопросов: 4 Ответов: 32 |
Профиль | Цитата | #3 | Добавлено: 22.02.08 17:54 |
Ничего не получается.
И вообще, я немного не понял строку Dim myDelegate As New SetClipboardText(AddressOf ChangeProperty) Привожу упрощенный пример своего программного кода: Imports System.Threading
Imports System.IO Public Class frmStatus Public Event FileDone() Public WithEvents FO As New FileOperations Dim Thrd As New Thread(AddressOf FO.Copy) 'Запуск процедуры в классе Public tPath As String Private Sub frmStatus_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.Show() Me.Refresh() StartOperation() End Sub Public Sub StartOperation() Dim i As Integer With frmMain.LV For i = 0 To .Items.Count - 1 'все проверки и передача значений через класс в другой поток '...... FO.FileList.Add(tFile) Next End With 'передача пути FO.tPath = tPath 'Запуск метода класса в другом потоке Thrd.Start() End Sub Private Sub FO_Done() Handles FO.Done ![]() End Sub Class FileOperations Public Class LFile Dim _Name As String Dim _Path As String Public Property Name() '... End Property Public Property Path() '... End Property End Class 'Передаем в другой поток через класс параметры Public FileList As New ArrayList Public tPath As String 'Читаем из потока через класс значения Public curFile As String Public curPercent As Double Public Event Done() Public Sub Copy() Dim MyDelegatePB As New DelegatePBChangeValue(AddressOf frmStatus.PBChangeValue) Dim i As Long Dim tPer As Double Dim cPer As Double Dim tFile As LFile cPer = 100 / FileList.Count For i = 0 To FileList.Count - 1 tFile = CType(FileList(i), LFile) curFile = tFile.Name 'нужно изменить значения лэйблов File.Copy(tFile.Path, Path.Combine(tPath, tFile.Name)) tPer += cPer curPercent = tPer MyDelegatePB.Invoke() 'нужно изменить значение прогрессбара Next RaiseEvent Done() End Sub End Class End Class Помогите дописать код. В местах "нужно изменить значение..." нужно взаимодействовать с интерфейсом. |
Номер ответа: 4 Автор ответа: ![]() ![]() ![]() ![]() Вопросов: 4 Ответов: 32 |
Профиль | Цитата | #4 | Добавлено: 22.02.08 17:57 |
З.Ы. На строку Dim MyDelegatePB As New DelegatePBChangeValue(AddressOf frmStatus.PBChangeValue) не обращайте внимания. Забыл удалить.
|
Номер ответа: 5 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ICQ: 318170731 Вопросов: 15 Ответов: 96 |
Профиль | Цитата | #5 | Добавлено: 22.02.08 18:11 |
извиняюсь "![]() в моем примере вместо SetClipboardText, надо использовать DelegateChangeProperty |
Номер ответа: 6 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ICQ: 318170731 Вопросов: 15 Ответов: 96 |
Профиль | Цитата | #6 | Добавлено: 22.02.08 18:26 |
Imports System.Threading
Imports System.IO Public Class frmStatus Public Event FileDone() Public WithEvents FO As New FileOperations ![]() Public tPath As String Private Sub frmStatus_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.Show() Me.Refresh() StartOperation() End Sub '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Sub PBChangeValue(ByVal curFile As String, ByVal curPercent As Double) ' туд делаем что то с прогрессбаром и т.д. End Sub '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Sub StartOperation() ![]() With frmMain.LV For i = 0 To .Items.Count - 1 'все проверки и передача значений через класс в другой поток '...... FO.FileList.Add(tFile) Next End With 'передача пути FO.tPath = tPath 'Запуск метода класса в другом потоке Thrd.Start() End Sub Private Sub FO_Done() Handles FO.Done ![]() End Sub Class FileOperations Public Class LFile ![]() ![]() Public Property Name() '... End Property Public Property Path() '... End Property End Class 'Передаем в другой поток через класс параметры Public FileList As New ArrayList Public tPath As String 'Читаем из потока через класс значения Public curFile As String Public curPercent As Double Public Event Done() '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Delegate Sub DelegatePBChangeValue(ByVal curFile As String, ByVal curPercent As Double) '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Sub Copy() '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ![]() '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ![]() ![]() ![]() ![]() cPer = 100 / FileList.Count For i = 0 To FileList.Count - 1 tFile = CType(FileList(i), LFile) curFile = tFile.Name 'нужно изменить значения лэйблов File.Copy(tFile.Path, Path.Combine(tPath, tFile.Name)) tPer += cPer curPercent = tPer '''''''''''''''''''''''''''''''''''''''''''''' MyDelegatePB.Invoke(curPercent, curFile) '''''''''''''''''''''''''''''''''''''''''''''' 'нужно изменить значение прогрессбара Next RaiseEvent Done() End Sub End Class End Class |
Номер ответа: 7 Автор ответа: ![]() ![]() ![]() ![]() Вопросов: 4 Ответов: 32 |
Профиль | Цитата | #7 | Добавлено: 22.02.08 19:35 |
Спасибо большое! Помогло!
Осталось только одно но: Данные передаются нормально. А вот обновляется не моя форма, которая на экране, а ее инстанс. Причем откуда он создался для меня загадка. Буду бороться дальше. З.Ы. Главная форма открывает диалоговую. Диалоговая при загрузке вызывает подрограмму, которая запускает поток. А вот обновляется не форма, а инстанс. Может поможете переиграть эту нерабочую схему? ![]() |
Номер ответа: 8 Автор ответа: ![]() ![]() ![]() ![]() Вопросов: 4 Ответов: 32 |
Профиль | Цитата | #8 | Добавлено: 22.02.08 20:31 |
И каким образом возник этот инстанс? |
Номер ответа: 9 Автор ответа: ![]() ![]() ![]() ![]() Вопросов: 4 Ответов: 32 |
Профиль | Цитата | #9 | Добавлено: 23.02.08 03:16 |
Просидев еще несколько часов, я пришел к выводу: Данные из другого потока действительно передаются в обработчик. И обработчик действительно меняет свойства контролов. И прочитать я могу эти значения. Но они не обновляются в модальном окне. А если вызвать метод Show, то появляется другое окно, в котором и происходят обновления. Но это окно ведет себя так, будто оно находится во втором потоке. И в этом же обработчике я не могу изменить свойства контролов главного окна. Вернее могу, но изменения касаются "другого" главного окна. "Паралельного".
Надеюсь, последний вопрос: Как грамотно (в какой последовательности) сделать следующее (из главной формы): 1. Передать потоку входящие параметры (скорее всего через класс, но может есть другие способы) 2. Открыть модальное окно статуса выполнения. (которое заблокирует основное до окончания действия) 3. Запустить второй поток. 4. В момент выполнения второго потока обновлять свойства контролов модального окна. 5. По завершении потока сообщить об этом основному потоку. Я знаю, что звучит это все довольно банально, но у меня почему-то не работает. И я не знаю где ошибка: в способе открытия модального окна, в вызове второго потока, в способе общения между потоками или ... в моем ДНК (шутка ![]() Если кто-то еще читает этот пост, пАмАгите пожалуйста. Очень хочу освоить многопоточность. В книгах есть масса примеров, и ни одного по моему вопросу. |
Номер ответа: 10 Автор ответа: ![]() ![]() Вопросов: 1 Ответов: 111 ![]() |
Профиль | Цитата | #10 | Добавлено: 23.02.08 08:57 |
Если кто-то еще читает этот пост, пАмАгите пожалуйста
Могу набросать пример, но на С#(ввиду отсутствия VB).. осилишь? |
Номер ответа: 11 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ICQ: 318170731 Вопросов: 15 Ответов: 96 |
Профиль | Цитата | #11 | Добавлено: 23.02.08 10:48 |
я бы посоветовал использовать интерфейс BackgroundWorker, в нем реализованы события запуск , изменение в потоке, завершение потока!
В данном примере я бы поступил так: 1) myThread.Start(параметры), параметры - можно описать в виде структуры или класса, что собственно не ограничивает набор параметров 2) запустить дополнительный поток 3) показать модальное окно, которое будет отображать ход выполнения (ShowDialog - метод, который запускает именно в модальном режиме) 4) c помощью делегата изменять свойства диалога 5) по окончанию работы доп. потока скрыть и освободить диалог |
Номер ответа: 12 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ICQ: 318170731 Вопросов: 15 Ответов: 96 |
Профиль | Цитата | #12 | Добавлено: 23.02.08 10:52 |
A) System.ComponentModel.BackgroundWorker (методы другие, но план выполнения такой же как и для System.Threading.Thread)
Б) План действия расписан для System.Threading.Thread |
Номер ответа: 13 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Вопросов: 130 Ответов: 6602 |
Профиль | Цитата | #13 | Добавлено: 23.02.08 19:16 |
По поводу фантомной формы могу пояснить в чем проблема
Dim MyDelegatePB As New DelegatePBChangeValue(AddressOf сылка_на_форму.PBChangeValue)
В принципе интерисует этот кусок кода, какая именно ссылка передается? Чтоб фантомное окно не создавалось, заведи глобальную ссылку на свой экземпляр формы. |
Номер ответа: 14 Автор ответа: ![]() ![]() ![]() ![]() Вопросов: 4 Ответов: 32 |
Профиль | Цитата | #14 | Добавлено: 24.02.08 09:15 |
Сорри, за задержку с ответом. (Был на работе и только утром добрался до компа. оффтоп)
2 Steel Brand: К сожалению я пытался и через глобальную переменную, и по прямой ссылке запускать форму и ссылаться на нее. Результат одинаковый - неработает. ![]() 2 fluke: Спасибо за совет. Сегодня займусь реализацией. К вечеру отпишусь о результатах. ![]() |
Номер ответа: 15 Автор ответа: ![]() ![]() ![]() ![]() Вопросов: 4 Ответов: 32 |
Профиль | Цитата | #15 | Добавлено: 24.02.08 09:16 |
Сорри, за задержку с ответом. (Был на работе и только утром добрался до компа. оффтоп)
2 Steel Brand: К сожалению я пытался и через глобальную переменную, и по прямой ссылке запускать форму и ссылаться на нее. Результат одинаковый - неработает. ![]() 2 fluke: Спасибо за совет. Сегодня займусь реализацией. К вечеру отпишусь о результатах. ![]() |
|