Visual Basic, .NET, ASP, VBScript
 

   
   
     

Форум - .NET

Страница: 1 | 2 |

 

  Вопрос: Обновление интерфейса из другого потока Добавлено: 22.02.08 07:45  

Автор вопроса:  Legon
Доброго времени суток! У меня возникла проблема: Приложение занимается копированием файлов. И делает это в другом потоке. Вопрос: Как из Второго потока(через делегаты, события или "заклинания" обновлять содержимое ProgressBar'a и Label'ов?

Я создал отдельный класс, через который передал другому потоку параметры для его запуска (список файлов для копирования и т.д.). В классе создал события, которые возникают при завершении копирования каждого файла, и эти события работают!... но в другом потоке.
Как мне обновлять ПрогрессБар по завершении копирования файла??? Или как мне инициализировать событие из кода второго процесса, а обработчик создать в основном?

Заранее спасибо!

Ответить

  Ответы Всего ответов: 19  

Номер ответа: 1
Автор ответа:
 fluke



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
Автор ответа:
 fluke



ICQ: 318170731 

Вопросов: 15
Ответов: 96
 Профиль | | #2 Добавлено: 22.02.08 10:40
P.S. - передачу параметров никто не отменял

Ответить

Номер ответа: 3
Автор ответа:
 Legon



Вопросов: 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
        ;DialogResult = Windows.Forms.DialogResult.OK
    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
Автор ответа:
 Legon



Вопросов: 4
Ответов: 32
 Профиль | | #4 Добавлено: 22.02.08 17:57
З.Ы. На строку
Dim MyDelegatePB As New DelegatePBChangeValue(AddressOf frmStatus.PBChangeValue)
не обращайте внимания. Забыл удалить.

Ответить

Номер ответа: 5
Автор ответа:
 fluke



ICQ: 318170731 

Вопросов: 15
Ответов: 96
 Профиль | | #5 Добавлено: 22.02.08 18:11
извиняюсь ";Dim myDelegate As New SetClipboardText(AddressOf ChangeProperty)" - остатки моего кода
в моем примере вместо SetClipboardText, надо использовать DelegateChangeProperty

Ответить

Номер ответа: 6
Автор ответа:
 fluke



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
    ;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

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Sub PBChangeValue(ByVal curFile As String, ByVal curPercent As Double)
        ' туд делаем что то с прогрессбаром и т.д.
    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
        ;DialogResult = Windows.Forms.DialogResult.OK
    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 Delegate Sub DelegatePBChangeValue(ByVal curFile As String, ByVal curPercent As Double)
        ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

        Public Sub Copy()

            ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
            ;Dim MyDelegatePB As New DelegatePBChangeValue(AddressOf сылка_на_форму.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(curPercent, curFile)
                ''''''''''''''''''''''''''''''''''''''''''''''

                'нужно изменить значение прогрессбара
            Next
            RaiseEvent Done()
        End Sub

    End Class

End Class

Ответить

Номер ответа: 7
Автор ответа:
 Legon



Вопросов: 4
Ответов: 32
 Профиль | | #7 Добавлено: 22.02.08 19:35
Спасибо большое! Помогло!
Осталось только одно но: Данные передаются нормально. А вот обновляется не моя форма, которая на экране, а ее инстанс. Причем откуда он создался для меня загадка. Буду бороться дальше.

З.Ы. Главная форма открывает диалоговую. Диалоговая при загрузке вызывает подрограмму, которая запускает поток. А вот обновляется не форма, а инстанс. Может поможете переиграть эту нерабочую схему? :)

Ответить

Номер ответа: 8
Автор ответа:
 Legon



Вопросов: 4
Ответов: 32
 Профиль | | #8 Добавлено: 22.02.08 20:31
И каким образом возник этот инстанс?

Ответить

Номер ответа: 9
Автор ответа:
 Legon



Вопросов: 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
Автор ответа:
 fluke



ICQ: 318170731 

Вопросов: 15
Ответов: 96
 Профиль | | #11 Добавлено: 23.02.08 10:48
я бы посоветовал использовать интерфейс BackgroundWorker, в нем реализованы события запуск , изменение в потоке, завершение потока!

В данном примере я бы поступил так:
1) myThread.Start(параметры), параметры - можно описать в виде структуры или класса, что собственно не ограничивает набор параметров
2) запустить дополнительный поток
3) показать модальное окно, которое будет отображать ход выполнения (ShowDialog - метод, который запускает именно в модальном режиме)
4) c помощью делегата изменять свойства диалога
5) по окончанию работы доп. потока скрыть и освободить диалог


Ответить

Номер ответа: 12
Автор ответа:
 fluke



ICQ: 318170731 

Вопросов: 15
Ответов: 96
 Профиль | | #12 Добавлено: 23.02.08 10:52
A) System.ComponentModel.BackgroundWorker (методы другие, но план выполнения такой же как и для System.Threading.Thread)

Б) План действия расписан для System.Threading.Thread

Ответить

Номер ответа: 13
Автор ответа:
 Artyom



Разработчик

Вопросов: 130
Ответов: 6602
 Профиль | | #13 Добавлено: 23.02.08 19:16
По поводу фантомной формы могу пояснить в чем проблема

Dim MyDelegatePB As New DelegatePBChangeValue(AddressOf сылка_на_форму.PBChangeValue)

В принципе интерисует этот кусок кода, какая именно ссылка передается?

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

Ответить

Номер ответа: 14
Автор ответа:
 Legon



Вопросов: 4
Ответов: 32
 Профиль | | #14 Добавлено: 24.02.08 09:15
Сорри, за задержку с ответом. (Был на работе и только утром добрался до компа. оффтоп)

2 Steel Brand: К сожалению я пытался и через глобальную переменную, и по прямой ссылке запускать форму и ссылаться на нее. Результат одинаковый - неработает. :(

2 fluke: Спасибо за совет. Сегодня займусь реализацией. К вечеру отпишусь о результатах. ;)

Ответить

Номер ответа: 15
Автор ответа:
 Legon



Вопросов: 4
Ответов: 32
 Профиль | | #15 Добавлено: 24.02.08 09:16
Сорри, за задержку с ответом. (Был на работе и только утром добрался до компа. оффтоп)

2 Steel Brand: К сожалению я пытался и через глобальную переменную, и по прямой ссылке запускать форму и ссылаться на нее. Результат одинаковый - неработает. :(

2 fluke: Спасибо за совет. Сегодня займусь реализацией. К вечеру отпишусь о результатах. ;)

Ответить

Страница: 1 | 2 |

Поиск по форуму



© Copyright 2002-2011 VBNet.RU | Пишите нам