Вопрос: Как обновить TreeView в реальном времени данными из другого потока?

Лучший ответ:
ну во первых посмотрите, что такое ленивое добавление узлов, и доступ к UI Thread осуществлять через Application.Current.Dispatcher

Худший ответ:
Я решил эту проблему.
Для начала запустил метод в новом потоке:private void FrOpcBrowser_Shown(object sender, EventArgs e)
        {
            try
            {
                currentServer.Connect(serverID);
                Text = serverID;
                treeView1.Nodes.Clear();
                treeView1.Nodes.Add(new TreeNode(serverID));
                treeView1.SelectedNode = treeView1.Nodes[0];
                TreeNode startNode = treeView1.SelectedNode;
                Thread thread = new Thread(delegate () { DoBrowse(startNode, -1); });
                thread.Start();
            }
            catch(Exception)
            {
                MessageBox.Show("Oops");
                Close();
            }
        }
Затем, когда метод DoBrowse проверит все условия, то запускается метод RecureBrowseprivate void DoBrowse(TreeNode startNode, int depth)
        {
            try
            {
                OPCNAMESPACETYPE opcOrgi = currentServer.QueryOrganization();

                if (opcOrgi == OPCNAMESPACETYPE.OPC_NS_HIERARCHIAL)
                {
                    //Устанавливем курсор на корневой узел дерева сервера
                    currentServer.ChangeBrowsePosition(OPCBROWSEDIRECTION.OPC_BROWSE_TO, "");
                    //Проверяем не является ли выбранный узел корнем сервера
                    if (startNode.FullPath.Length > serverID.Length)
                    {
                        //Если выбранный узел не корень сервера, то получаем полный путь для данного узла
                        string[] splitpath = startNode.FullPath.Substring(serverID.Length + 1).Split(new char[] { '\t', '\\' });
                        //Имея полный путь, спускаемся до выбранного узла на сервере
                        foreach (string n in splitpath)
                        {
                            currentServer.ChangeBrowsePosition(OPCBROWSEDIRECTION.OPC_BROWSE_DOWN, n);
                        }
                    }
                    RecurBrowse(startNode, depth);
                }
            }
            catch(Exception)
            {
                MessageBox.Show("browse error!", "DoBrowse", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            return;
        }

        private bool RecurBrowse(TreeNode startNode, int depth)
        {
            try
            {
                if (depth == 0)
                {
                    return true;
                }
                currentServer.Browse(OPCBROWSETYPE.OPC_BRANCH, out ArrayList lst);
                if (lst == null || lst.Count < 1)
                {
                    return true;
                }

                foreach(string branch in lst)
                {
                    TreeNode nextNode = new TreeNode(branch);
                    AddNode(startNode, nextNode);
                    currentServer.ChangeBrowsePosition(OPCBROWSEDIRECTION.OPC_BROWSE_DOWN, branch);
                    RecurBrowse(nextNode, depth - 1);
                    currentServer.ChangeBrowsePosition(OPCBROWSEDIRECTION.OPC_BROWSE_UP, "");
                    
                }
            }
            catch(Exception)
            {
                MessageBox.Show(this, "browse error!", "RecurBrowse", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return false;
            }
            return true;
        }
В методе RecureBrowse добавление новой ноды происход вызовом метода AddNode, который вызывается (как я понял) в том потоке, которому принадлежит родительская нода.private void AddNode(TreeNode parentNode, TreeNode childNode)
        {
            if (InvokeRequired)
            {
                Invoke(new Action<TreeNode, TreeNode>(AddNode), new TreeNode[] { parentNode, childNode });
                return;
            }
            parentNode.Nodes.Add(childNode);
        }
Работает медленно, но работает :)