在执行任务时允许主(gui)线程,然后更新表

时间:2018-10-23 06:28:36

标签: c# multithreading datagridview task

我正在使用Winform尝试收集网络上每个IP的在线/离线状态,这样做是在使用ping请求,如果它答复将IP标记为在线然后继续。唯一的问题是等待最多255个答复,在它获得所有255个答复后,我希望它填充数据网格视图。

我设法使所有功能正常工作,但唯一的缺点是,gui在执行此过程时会挂起,我想只是使用带有以下表达式的单独线程

Thread T1 = new Thread(PingHost)
T1.run();

PingHost顾名思义,对所有主机执行ping操作并确定是联机还是脱机。问题是我试图从线程更新dgv表,自然dgv被锁定到主线程。

所以我尝试切换到一个任务,只是获取返回值并在完成所有操作后进行更新。可悲的是,我无法完全了解如何从任务中获取返回值并使它在单独的线程上运行。

我尝试使用谷歌搜索不同的方法,但是此时我只是围着圈跑,所以我很谦虚地向你们寻求帮助

使用任务的主线程代码

List<string> everything = new List<string>();

        int i = 0;


        Task<List<string>> task1 = Task<List<string>>.Factory.StartNew(PingHost);
        everything = task1.Result;
        foreach(var item in everything)
        {
            var index = dataGridView1.Rows.Add();
            dataGridView1.Rows[i].Cells["IP"].Value = item;
            i++;
        }

这是我的PingHost方法的线程

bool pingable = false;
        Ping pinger = null;
        int i = 0;

        string ip;
        while (i < 255)
        {
             ip = "192.168.0." + i;
            try
            {
                pinger = new Ping();
                PingReply reply = pinger.Send(ip, 8);
                pingable = reply.Status == IPStatus.Success;
            }
            catch (PingException)
            {
                MessageBox.Show("ERROR");
                // Discard PingExceptions and return false;
            }
            finally
            {
                if (pinger != null)
                {
                    pinger.Dispose();
                }
            }
            if (pingable)
            {
                checkedIP.Add(ip + ": ONLINE");
            }
            else
            {
            checkedIP.Add(ip + ": OFFLINE");

            }
            i++;
        }
        return checkedIP;

1 个答案:

答案 0 :(得分:0)

这可能有点矫kill过正,但我​​只是草拟了一个解决方案。基本上,我创建了一个用于ping的新类,该事件在每次Ping返回后触发,该事件使用自定义EventArgs返回刚刚被ping的IP(无论它是否在线)。然后,我在GUI线程中订阅了该事件,然后更新了GUI。这是一些代码:

这是我的Pinger班,负责对实际的计算机执行ping操作:

class Pinger
{
    public event EventHandler<PingReturnedEventArgs> OnPingReturned;

    public void PingNetwork()
    {
        for (int i = 1; i <= 255; i++)
        {
            string ip = $"192.168.0.{i}";

            Ping ping = new Ping();

            try
            {
                PingReply reply = ping.Send(IPAddress.Parse(ip));
                TriggerEvent(reply?.Address.ToString(), true);
            }
            catch (Exception)
            {
                TriggerEvent(ip, false);
            }
        }
    }

    private void TriggerEvent(string ip, bool online)
    {
        if (OnPingReturned == null) return;

        PingReturnedEventArgs args = new PingReturnedEventArgs(ip, online);
        OnPingReturned(this, args);
    }
}

我的自定义EventArgs:

class PingReturnedEventArgs : EventArgs
{
    public string Ip { get; private set; }

    public bool Online { get; private set; }

    private PingReturnedEventArgs() { }

    public PingReturnedEventArgs(string ip, bool online)
    {
        Ip = ip;
        Online = online;
    }
}

最后这就是我实际上如何使用所有这些的方法:

Pinger pinger = new Pinger();
pinger.OnPingReturned += Your event handler to update the GUI

// I recommend doing it like this so you can stop the Thread at a later time
// Maybe with like a cancel button
Thread pingThread = new Thread(pinger.PingNetwork);
pingThread.Start();

事件处理程序看起来像这样private void PingReturnedHandler(object sender, PingReturnedEventArgs args)

此操作的两个主要好处是:1. GUI线程保持未阻塞,这意味着GUI仍将响应用户输入; 2.此过程(在每次ping操作完成时)触发事件,这意味着如果花费很长时间是时候对所有PC进行ping操作了,您不必在用户看到某些东西之前就等待整个操作完成

相关问题