【问题标题】:UI not updating while looping through IP Addresses循环通过 IP 地址时 UI 未更新
【发布时间】:2020-08-10 14:26:12
【问题描述】:

我有一个简单的工作要做,点击按钮它将从一个范围内获取所有网络 IP 地址,循环通过它们并将活动放在一个列表中。在执行该过程时,将显示一个面板,其中将显示正在检查的 IP 地址。代码运行良好,但表单挂起,应用程序没有响应,即使面板没有显示,IP 地址也没有显示。怎么做? 我的代码是:

private void btnAutoSearch_Click(object sender, EventArgs e)
    {
        panel_Search.Visible = true; // Not Working
        Cursor.Current = Cursors.WaitCursor;

        string ipBase = getIPAddress();
        string[] ipParts = ipBase.Split('.');
        ipBase = ipParts[0] + "." + ipParts[1] + "." + ipParts[2] + ".";



        for (int i = 1; i < 255; i++)
        {
            string ip = ipBase + i.ToString();
            Ping p = new Ping();                
            PingReply pingresult = p.Send(ip, 100);
            if (pingresult.Status == IPStatus.Success)
            {
                lstIPs.Add(ip);
                lblConnecting.Text = ip;  // Not Working

            }

        }


        GridConn.Rows.Clear();
        foreach (string s in lstIPs)
        {
            Device obj = new Device();
            obj.IPAddress = s;
            lblConnecting.Text = s;
            int vSMSLimit = 0;
            int.TryParse(txtSMSLimit.Text, out vSMSLimit);
            obj.SMSLimit = 0;
            if (obj.ConnectToHostServer())
            {
                obj.SendConnectionMessage();
                obj.ReceiveConnectionMessage();
                MyDevices.lst.Add(obj);
                GridConn.Rows.Add(true, obj.IPAddress, obj.PhoneModel, obj.PhoneStatus, obj.SoftwareVersion);
            }
        }


         Cursor.Current = Cursors.Default;
        panel_Search.Visible = false;
    }

【问题讨论】:

标签: c# winforms loops user-interface


【解决方案1】:

问题是 UI 必须从“主”线程(通常称为 UI 线程)更新,但如果您在此线程上执行其他处理,则 UI 本身将锁定。所以你应该把长时间运行的进程放到另一个线程上。

这将导致问题,但是该线程无法更新 UI,因为它不是 Main/UI 线程。所以你必须自己调用 UI 线程来更新它。

幸运的是,有一种简单的方法可以使用 C# 中的 BackgroundWorker 类来执行此操作,这对您有很大帮助。但是您需要将 UI 和后台任务分开。

//Define worker
BackgroundWorker myBGWorker;


//Initalise worker and start it from your button
private void btnAutoSearch_Click(object sender, EventArgs e)
{
    panel_Search.Visible = true; // Not Working
    Cursor.Current = Cursors.WaitCursor;

    myBGWorker = new BackgroundWorker()

    //This method will execute your processing on a background thread
    myBGWorker.DoWork += new DoWorkEventHandler(bgw_DoWork);

    //This method will execute when your background worker finishes
    //It runs on the Main/UI thread
    myBGWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);

    //This method will execute when the background thread wants to update the progress
    //It runs on the Main/UI Thread
    myBGWorker.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged);

    //Tell it we will be reporting progress
    myBGWorker.WorkerReportsProgress = true;

    //Start!
    myBGWorker.RunWorkerAsync()
}

private void bgw_DoWork(object sender, DoWorkEventArgs e)  
{  
        string ipBase = getIPAddress();
        string[] ipParts = ipBase.Split('.');
        ipBase = ipParts[0] + "." + ipParts[1] + "." + ipParts[2] + ".";

        for (int i = 1; i < 255; i++)
        {
            string ip = ipBase + i.ToString();
            Ping p = new Ping();                
            PingReply pingresult = p.Send(ip, 100);
            if (pingresult.Status == IPStatus.Success)
            {
                lstIPs.Add(ip);

                //Below reports the progress.  The number shouuld represent the percentage of process, the object can be anything you want
                double percentDone = (100.0 / 255.0) * i;            
                e.ReportProgress(Convert.ToInt32(percentDone), ip);
            }

        }
}  

private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    lblConnecting.Text = e.UserState as string;  
}


private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{
    if (e.Cancelled) 
        MessageBox.Show("Operation was canceled");  
    else if (e.Error != null) 
        MessageBox.Show(e.Error.Message);  
    else 
    {
       GridConn.Rows.Clear();
        foreach (string s in lstIPs)
        {
            Device obj = new Device();
            obj.IPAddress = s;
            lblConnecting.Text = s;
            int vSMSLimit = 0;
            int.TryParse(txtSMSLimit.Text, out vSMSLimit);
            obj.SMSLimit = 0;
            if (obj.ConnectToHostServer())
            {
                obj.SendConnectionMessage();
                obj.ReceiveConnectionMessage();
                MyDevices.lst.Add(obj);
                GridConn.Rows.Add(true, obj.IPAddress, obj.PhoneModel, obj.PhoneStatus, obj.SoftwareVersion);
            }
        }

        Cursor.Current = Cursors.Default;
        panel_Search.Visible = false;
    }
}

【讨论】:

    【解决方案2】:

    桌面应用程序使用单个线程来处理 UI,并且事件处理程序在 UI 线程上同步运行,这就是表单挂起的原因,因为它无法在事件处理程序运行时处理其他 UI 交互。

    最佳实践是事件处理程序占用 UI 线程的时间很短。

    当您因为用户交互需要执行长时间运行的任务时,您应该在另一个线程中执行该任务,您不应该使用 UI 线程来执行长时间运行的任务。

    您可以使用 BackgroundWorker 将任务移动到另一个线程,但最好使用异步事件处理程序。

    例如:

    private async void myButton_Click(object sender, EventArgs e)
    {
        await PerformLongRunningTaskAsync();
        //TODO: update UI after completing task
    
        await Task.Run(() => PerformLongRunningTaskSynchronously());
        //TODO: update UI after completing task;
    }
    
    private async Task PerformLongRunnigTaskAsync() {
       //TODO: implement this async method
    }
    
    private void PerformLongRunningTaskSynchronously() {
      //TODO: implement this synchronus method
    }
    

    你的代码应该是这样的:

    private async void btnAutoSearch_Click(object sender, EventArgs e)
        {
            panel_Search.Visible = true; // Not Working
            Cursor.Current = Cursors.WaitCursor;
    
            string ipBase = getIPAddress();
            string[] ipParts = ipBase.Split('.');
            ipBase = ipParts[0] + "." + ipParts[1] + "." + ipParts[2] + ".";
    
    
    
            for (int i = 1; i < 255; i++)
            {
                string ip = ipBase + i.ToString();
                Ping p = new Ping();                
                PingReply pingresult = await p.SendPingAsync(ip, 100);
                if (pingresult.Status == IPStatus.Success)
                {
                    lstIPs.Add(ip);
                    lblConnecting.Text = ip;  // Not Working
    
                }
    
            }
    
    
            GridConn.Rows.Clear();
            foreach (string s in lstIPs)
            {
                Device obj = new Device();
                obj.IPAddress = s;
                lblConnecting.Text = s;
                int vSMSLimit = 0;
                int.TryParse(txtSMSLimit.Text, out vSMSLimit);
                obj.SMSLimit = 0;
                if (await Task.Run(() => obj.ConnectToHostServer())
                {
                    await Task.Run(() => obj.SendConnectionMessage());
                    await Task.Run(() => obj.ReceiveConnectionMessage());
                    MyDevices.lst.Add(obj);
                    GridConn.Rows.Add(true, obj.IPAddress, obj.PhoneModel, obj.PhoneStatus, obj.SoftwareVersion);
                }
            }
    
    
             Cursor.Current = Cursors.Default;
            panel_Search.Visible = false;
        }
    

    【讨论】:

      【解决方案3】:

      感谢 Brian Rogers,这是我的工作方式,

       private void btnAutoSearch_Click(object sender, EventArgs e)
          {
      
              backgroundWorker1.WorkerSupportsCancellation = true;
      
      
              if (backgroundWorker1.IsBusy != true)
              {
                  // Start the asynchronous operation.
                  backgroundWorker1.RunWorkerAsync();
              }
      
          }
      
      private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
          {
              BackgroundWorker worker = sender as BackgroundWorker;
      
              for (int j = 1; j <= 10; j++)
              {
                  if (worker.CancellationPending == true)
                  {
                      e.Cancel = true;
                      break;
                  }
                  else
                  {
                      Cursor.Current = Cursors.WaitCursor;
                      panel_Search.Location = new Point(380, 72);
                      // Perform a time consuming operation and report progress.
                      string ipBase = getIPAddress();
                      string[] ipParts = ipBase.Split('.');
                      ipBase = ipParts[0] + "." + ipParts[1] + "." + ipParts[2] + ".";
      
      
      
                      for (int i = 1; i < 255; i++)
                      {
                          string ip = ipBase + i.ToString();
                          Ping p = new Ping();                                                
      PingReply pingresult = p.Send(ip, 100);
                          if (pingresult.Status == IPStatus.Success)
                          {
                              lstIPs.Add(ip);                            
                              lblConnecting.Text = ip;
                              //listBox1.Items.Add(ip);                
                          }
      
                      }
      
      
      
      
                      GridConn.Rows.Clear();
                      foreach (string s in lstIPs)
                      {
                          Device obj = new Device();
                          obj.IPAddress = s;
                          lblConnecting.Text = s;
                          int vSMSLimit = 0;
                          int.TryParse(txtSMSLimit.Text, out vSMSLimit);
                          obj.SMSLimit = 0;
                          if (obj.ConnectToHostServer())
                          {
                              obj.SendConnectionMessage();
                              obj.ReceiveConnectionMessage();
                              MyDevices.lst.Add(obj);
                              GridConn.Rows.Add(true, obj.IPAddress, obj.PhoneModel, obj.PhoneStatus, obj.SoftwareVersion);
                          }
                      }
      
                      Cursor.Current = Cursors.Default;
                      panel_Search.Location = new Point(333, 252);
      
                  }
              }
          }
      

      【讨论】:

        猜你喜欢
        • 2023-02-22
        • 2016-07-21
        • 2010-09-09
        • 1970-01-01
        • 2013-08-25
        • 1970-01-01
        • 2011-05-30
        • 2015-06-18
        • 2021-06-09
        相关资源
        最近更新 更多