Блокировка элемента управления из другого потока в Visual Basic - PullRequest
1 голос
/ 19 марта 2011

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

-Proc1
  -Proc2
    -Proc3
  -Proc4
-Proc2
  -Proc3
-Proc3
-Proc4

Теперь все мои разборы работают правильно.Хотя этот процесс довольно длительный.Поэтому я решил перенести всю тяжеловесную обработку на собственный поток.Все работает так, как задумано, пока я не дохожу до того, что мне нужно обновить TreeView.Я пытаюсь сохранить всю актуальную логику обновления в отдельном потоке и обновлять только TreeView.Однако, несмотря на мою основную форму SyncLocked, я все еще получаю исключение, когда пытаюсь получить доступ к дереву.

В Интернете я нашел довольно много примеров, которые показывают, как использовать Делегаты для многопоточного доступа, но,к сожалению, все они немного упрощены для моих нужд.Наиболее просто показать, как установить свойство текста.Как я упоминал ранее, я пытаюсь сохранить как можно большую часть обработки в рабочем потоке и вызывать только соответствующие методы TreeView для обновления, поскольку этот процесс может быть довольно длительным (сотни процедур для анализа и отображения одновременно).

Есть ли хороший способ сделать это или я должен просто взять свои комки и передать все дерево зависимостей обратно в основную форму?

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

Public Sub updateTreeView()

    Dim arrNodeList As ArrayList
    Dim childNode As clsProcedureNode
    Dim currentNode As clsProcedureNode
    Dim intChildIndex As Integer
    Dim intNodeListIndex As Integer
    Dim treeView As TreeView

    //Lock main form
    SyncLock mMainForm

        //Check that we are actually running on a seprate thread
        If mMainForm.InvokeRequired() = True Then

            //Call delegate to get handle to TreeView
            treeView = mMainForm.Invoke(mGetTreeViewDelegate)

            //Add Parsed array to main form TreeView
            For intNodeListIndex = 0 To mProcedureNodes.Length - 1

                //Get current node and its child list
                currentNode = mProcedureNodes(intNodeListIndex)
                arrNodeList = currentNode.getProcsCalled()

                //Add node and all children to TreeView
                With treeView
                    .BeginUpdate()
                    .Nodes.Add(currentNode.getName())
                    For intChildIndex = 0 To arrNodeList.Count
                        childNode = arrNodeList.Item(intChildIndex)
                        .Nodes(intNodeListIndex).Nodes.Add(childNode.getName())
                    Next
                    .EndUpdate()
                End With
            Next
        End If   
    End SyncLock   
End Sub

Ответы [ 2 ]

2 голосов
/ 19 марта 2011

Почему бы вам не использовать BackgroundWorker ? Это намного проще в использовании, чем Invoke и синхронизация. На самом деле, он был разработан, чтобы облегчить подобные вещи.

Вы можете выполнять фоновую работу в DoWork обработчике событий, который работает в другом потоке и безопасно взаимодействовать с вашим пользовательским интерфейсом в ProgressChanged обработчике событий, который выполняется в потоке пользовательского интерфейса. Необходимость вызова ProgressChanged сигнализируется в DoWork с использованием ReportProgress метода BackgroundWorker.

0 голосов
/ 19 марта 2011

Ну, единственное место, где можно безопасно манипулировать элементами управления пользовательским интерфейсом - это поток пользовательского интерфейса. Это так в WinForms, а также в WPF. Вы можете либо вернуть данные в поток пользовательского интерфейса и заполнить там все дерево, либо сделать что-то вроде этого (псевдокод):

Sub updateView()
   foreach item in data
      mainForm.AddToTreeView(item);
      Thread.Sleep(1);

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...