0

我有一个简单的 WindowsForm 应用程序,其中包含 TreeView。初始化时 - TreeView 使用默认 imageIndexes 从 XML 构建。我的 TreeView 由服务器名称组成。在标签元素中,我放置了由主机和 IP 组成的字典。初始化后我调用方法,如果服务器超时,则更改 imageIndex。我需要在非阻塞主线程(GUI)的 BackgroundWorker 中调用此方法。我计划每分钟运行一次这个方法。下面是这个方法:

    private void checkServersTree()
    {
        TreeNodeCollection rootNodes = treeViewSrv.Nodes;
        TreeNodeCollection childNodes;
        PingServers ps = new PingServers();
        for (int i = 0; i < rootNodes.Count; i++)
        {
            childNodes = treeViewSrv.Nodes[i].Nodes;
            treeViewSrv.Nodes[i].Text += string.Format(" ({0})", childNodes.Count);
            int downServers = 0;
            foreach (TreeNode tNode in childNodes)
            {
                if (tNode.Tag != null)
                {
                    Dictionary<string, string> dicParams = tNode.Tag as Dictionary<string, string>;

                    if (!ps.getServerStatus(dicParams["host"], dicParams["ip"]))
                    {
                        tNode.ImageIndex = 1;   //red
                        rootNodes[i].ImageIndex = 2;   //yellow
                        downServers++;
                    }
                }
            }

            if(downServers == childNodes.Count)
                rootNodes[i].ImageIndex = 4;   //fatal red
        }
    }

提前致谢!


感谢您的回答!在我写到这里之前,我阅读了 Invoke 和 BeginInvoke。但我无法解决这个问题 - 运行更改 TreeView ImageIndexes 的异步线程。我去找您的链接并编写了代码(如下),但 GUI 仍然被阻止。我究竟做错了什么?

namespace CCCServers
{
    public partial class CCCServers : Form
    {
        public delegate void checkSrvDelegate();
        public checkSrvDelegate myDelegate;
        private Thread myThread;

        public CCCServers()
        {
            InitializeComponent();

            TreeFromXML tfXML = new TreeFromXML(treeViewSrv, "../../Servers.xml");
            tfXML.initTreeNodesFromXML();

            treeViewSrv.ExpandAll();

            //checkServersTree();
            myDelegate = new checkSrvDelegate(checkServersTree);
        }

        private void checkServersTree()
        {
            TreeNodeCollection rootNodes = treeViewSrv.Nodes;
            TreeNodeCollection childNodes;
            PingServers ps = new PingServers();
            for (int i = 0; i < rootNodes.Count; i++)
            {
                childNodes = treeViewSrv.Nodes[i].Nodes;
                treeViewSrv.Nodes[i].Text += string.Format(" ({0})", childNodes.Count);
                int downServers = 0;
                foreach (TreeNode tNode in childNodes)
                {
                    if (tNode.Tag != null)
                    {
                        Dictionary<string, string> dicParams = tNode.Tag as Dictionary<string, string>;

                        if (!ps.getServerStatus(dicParams["host"], dicParams["ip"]))
                        {
                            tNode.ImageIndex = 1;   //red
                            rootNodes[i].ImageIndex = 2;   //yellow
                            downServers++;
                        }
                    }
                }

                if(downServers == childNodes.Count)
                    rootNodes[i].ImageIndex = 4;   //fatal red
            }
        }

        private void btnRDP_Click(object sender, EventArgs e)
        {
            myThread = new Thread(new ThreadStart(threadFunction));
            myThread.Start();
        }

        private void threadFunction()
        {
            MyThreadClass myThreadClassObject = new MyThreadClass(this);
            myThreadClassObject.Run();
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            MessageBox.Show(e.Node.Text, "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void treeViewSrv_AfterSelect(object sender, TreeViewEventArgs e)
        {
            e.Node.SelectedImageIndex = e.Node.ImageIndex;  //Что бы иконка не менялась при выборе узла
        }
    }

    //***************************************************************************

    public class MyThreadClass
    {
        CCCServers cccSrv;
        public MyThreadClass(CCCServers myForm)
        {
            cccSrv = myForm;
        }

        public void Run()
        {
            cccSrv.Invoke(cccSrv.myDelegate);
        }
    }
}
4

2 回答 2

0

我解决了我的问题。在特殊位置插入我的代码后,Debug.WriteLine(String.Format("<<<<<<<< This is {0} thread", Thread.CurrentThread.ManagedThreadId));我意识到Control.Invoke在主线程中调用了Control.Invoke. 请看下面的代码:

private delegate void setServersCountDelegate(int idx, int cnt);
private delegate void setChldNodeImgIndexDelegate(TreeNode tNode, int imgIdx);

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    testBuildTree();
}

private void testBuildTree()
{
    Thread.CurrentThread.Name = "CheckServers";
    Debug.WriteLine(String.Format("|||||||||| This is {0} thread", Thread.CurrentThread.ManagedThreadId));
    changeImgIndex();
}

private void changeImgIndex()
{
    Debug.WriteLine(String.Format("--------- This is {0} thread", Thread.CurrentThread.ManagedThreadId));
    TreeNodeCollection rootNodes = treeViewSrv.Nodes;
    TreeNodeCollection childNodes;

    for (int i = 0; i < rootNodes.Count; i++)
    {
        childNodes = treeViewSrv.Nodes[i].Nodes;
        //treeViewSrv.Nodes[i].Text += string.Format(" ({0})", childNodes.Count);
        treeViewSrv.Invoke(new setServersCountDelegate(setServersCount), new object[] { i, childNodes.Count });
        int downServers = 0;
        foreach (TreeNode tNode in childNodes)
        {
            if (tNode.Tag != null)
            {
                Dictionary<string, string> dicParams = tNode.Tag as Dictionary<string, string>;

                if (!getServerStatus(dicParams["host"], dicParams["ip"]))
                {
                    Debug.WriteLine(String.Format("<<<<<<<< This is {0} thread", Thread.CurrentThread.ManagedThreadId));
                    //tNode.ImageIndex = 1;   //red
                    treeViewSrv.Invoke(new setChldNodeImgIndexDelegate(setChldNodeImgIndex), new object[] { tNode, 1 });    //red
                    //rootNodes[i].ImageIndex = 2;   //yellow
                    treeViewSrv.Invoke(new setChldNodeImgIndexDelegate(setChldNodeImgIndex), new object[] { rootNodes[i], 2 }); //yellow
                    downServers++;
                }
            }
        }

        if (downServers == childNodes.Count)
        {
            //rootNodes[i].ImageIndex = 4;   //fatal red
            treeViewSrv.Invoke(new setChldNodeImgIndexDelegate(setChldNodeImgIndex), new object[] { rootNodes[i], 4 });
        }
    }
}

private void setServersCount(int idx, int cnt)
{
    string[] spltNodeText = treeViewSrv.Nodes[idx].Text.Split(' ');
    treeViewSrv.Nodes[idx].Text = string.Format("{0} ({1})", spltNodeText[0], cnt);
}

private void setChldNodeImgIndex(TreeNode tNode, int imgIdx)
{
    tNode.ImageIndex = imgIdx;
}
于 2013-03-12T18:41:53.657 回答
0

您需要使用表单的Invoke方法在创建窗口句柄的线程上执行用户界面方法。例如

Invoke((Action) checkServersTree);
于 2013-03-06T21:56:27.877 回答