winform处理耗时操作

gudicao 2012-12-23 05:49:19
程序是扫描局域网里的主机:

public delegate void OnUiControl();
private void button1_Click(object sender, EventArgs e)
{
Thread thScan = new Thread(new ThreadStart(DoControl));
thScan.IsBackground = true;
thScan.Start();
}
private void DoControl()
{
OnUiControl uicontrol = this.ScanTarget;
if (this.InvokeRequired)
{
this.Invoke(uicontrol);
}
}

private void ScanTarget()
{
string strIPAddress = "172.30.81."; //ip段
int nStrat = Int32.Parse("2"); //开始扫描地址
int nEnd = Int32.Parse("50"); //终止扫描地址
//开始扫描(耗时操作)
for (int i = nStrat; i <= nEnd; i++)
{
string strScanIPAdd = strIPAddress + i.ToString();
IPAddress myScanIP = IPAddress.Parse(strScanIPAdd); //转换成IP地址
try
{
//当执行下面这个操作时候比较耗时
IPHostEntry myScanHost = Dns.Resolve(strScanIPAdd);
string strHostName = myScanHost.HostName;
richTextBox1.AppendText(strHostName + "\r");
Application.DoEvents();

}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
}


上面是原程序,为什么使用了多线程后界面还会卡死呢?求解
...全文
430 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
用的是VS2010的3.5的,改成4.0的就报错了,下面这样可以

public partial class FrmTest : Form
    {
        private Action<IPHostEntry> _reportIP;
        private int nStrat = 100, nEnd = 150;  //扫描地址范围
        private bool _asyCancellation = false;        

        public FrmTest()
        {
            InitializeComponent();            
        }

        private void ScanTarget()
        {
            string strIPAddress = "192.168.0."; //ip段
            //开始扫描(耗时操作)           
            for (int i = nStrat; i <= nEnd; i++)
            {
                if (this._asyCancellation) return;
                string strScanIPAdd = strIPAddress + i.ToString();
                IPAddress myScanIP = IPAddress.Parse(strScanIPAdd);    //转换成IP地址
                try
                {
                    //当执行下面这个操作时候比较耗时 
                    IPHostEntry myScanHost = Dns.Resolve(strScanIPAdd);
                    if (this.InvokeRequired)
                    {
                        this.Invoke(this._reportIP, myScanHost);
                    }
                    else
                    {
                        this._reportIP(myScanHost);
                    }
                }
                catch (Exception error)
                {
                    MessageBox.Show(error.Message);
                }
            }
        }

        private void OnResolvedCallback(IPHostEntry ip)
        {
            this.richTextBox1.AppendText(ip.HostName + "\r");
            //假设界面上还有一个进度条            
            var curIP = (int)ip.AddressList[0].GetAddressBytes().Last();
            var rate = (curIP - nStrat) / (double)(nEnd - nStrat);
            this.progressBar1.Value = Convert.ToInt32(rate * 100);            
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            if (!this._asyCancellation)
            {
                if (this._reportIP == null) this._reportIP = this.OnResolvedCallback;
                this.progressBar1.Value = this.progressBar1.Minimum;
                Thread thScan = new Thread(new ThreadStart(ScanTarget));
                thScan.IsBackground = true;
                thScan.Start();
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this._asyCancellation = true;
            this.progressBar1.Value = this.progressBar1.Maximum;
        }
    }
直接用BackgroundWoker省事多了
  • 打赏
  • 举报
回复
引用 3 楼 dongxinxi 的回复:
C# code?1234567891011121314151617181920212223242526272829303132private Action<string> _reportIP; private void button1_Click(object sender, EventArgs e) { /……
刚测了下,不会卡界面,是不是其他地方引起的?对界面的更新,都放那个委托里面
//回调处理
private Action<string> _reportIP;
private int nStrat = 2, nEnd = 50;  //扫描地址范围
//----上面是成员变量,放在方法外----

      private void button1_Click(object sender, EventArgs e)       
      {
            //回调处理可移到Form_Load中,如果其他的Form要用到,最好封装到事件中去
            this._reportIP = ip =>
            {
                this.richTextBox1.AppendText(ip + "\r");
                //假设界面上还有一个进度条
                int curIP = int.Parse(ip.Split(".").Last());
                this.progessBar1.Value = (curIP - nStrat) / (nEnd - nStrat) * 100;
                //继续加更新界面的代码...
            };
            Thread thScan = new Thread(new ThreadStart(ScanTarget));  
            thScan.IsBackground = true;            
            thScan.Start();
       }  
gudicao 2012-12-24
  • 打赏
  • 举报
回复
这个没有注释掉啊,我用的VS2010,你用的是哪个?可以私聊吗?
  • 打赏
  • 举报
回复
我又试了下,发现如果把Main函数上的[STAThread]注释掉,就会出现LZ所说的问题,但是其实这个标记是WinForm默认的,表示以单线程方式与COM组件之间进行通信。它并不会影响到你在Form里使用多线程技术,除非你用到了ActiveX或者第三方的软件COM
garfieldzf 2012-12-24
  • 打赏
  • 举报
回复
我测试了下也就是在扫描时拉动界面时会出现无响应
hzexe 2012-12-23
  • 打赏
  • 举报
回复

private void DoControl()        {            OnUiControl uicontrol = this.ScanTarget;            if (this.InvokeRequired)            {                this.Invoke(uicontrol);            }        }
this.Invoke方法会使用主线程去操作的。。。。 而这是应该用后台线程去操作耗时的东东。
gudicao 2012-12-23
  • 打赏
  • 举报
回复
那该怎么解决呢,如果不这样线程会出现"线程间间操作无效",我网上查了线程间操作的大都是用的this.Invoke()方法,或许我这样操作不对,给点思路也好
  • 打赏
  • 举报
回复
this.Invoke(uicontrol) 就是阻塞自己,直到主线程处理完这个uiconttol。 因此你的目地不但没有达到,反而比不用线程还要更糟。
gudicao 2012-12-23
  • 打赏
  • 举报
回复
该怎么解决呢,顶下啊
gudicao 2012-12-23
  • 打赏
  • 举报
回复
引用 3 楼 dongxinxi 的回复:
C# code ? 123456789101112131415161718192021222324252627282930313233 private Action<string> _reportIP; private void button1_Click(object sender, EventArgs e) { ……
这样直接调用会报"线程间操作无效"的
gudicao 2012-12-23
  • 打赏
  • 举报
回复
this.Invoke(uicontrol)是为了解决跨线程访问UI控件报错的问题,希望sp1234指导,我只是一个菜鸟
threenewbee 2012-12-23
  • 打赏
  • 举报
回复
http://download.csdn.net/detail/caozhy/4832657 参考这个例子。
  • 打赏
  • 举报
回复
引用 2 楼 gudicao 的回复:
可以详细点吗,直接调线程和调用辅助线程有什么区别吗?
你虽然写了一行代码进行所谓“使用多线程”,可是这个线程中立刻执行
this.Invoke(uicontrol);
这种多线程有什么意义呢?
  • 打赏
  • 举报
回复

private Action<string> _reportIP;
        private void button1_Click(object sender, EventArgs e)       
        {
            //回调处理
            this._reportIP = ip => this.richTextBox1.AppendText(ip + "\r");
            Thread thScan = new Thread(new ThreadStart(ScanTarget));  
            thScan.IsBackground = true;            
            thScan.Start();        
        }                   
        
        private void ScanTarget()   
        {           
            string strIPAddress = "172.30.81."; //ip段  
            int nStrat = Int32.Parse("2");   //开始扫描地址            
            int nEnd = Int32.Parse("50");  //终止扫描地址     
            //开始扫描(耗时操作)           
            for (int i = nStrat; i <= nEnd; i++)            
            {              
                string strScanIPAdd = strIPAddress + i.ToString();
                IPAddress myScanIP = IPAddress.Parse(strScanIPAdd);    //转换成IP地址
                try                 
                {                    
                    //当执行下面这个操作时候比较耗时 
                    IPHostEntry myScanHost = Dns.Resolve(strScanIPAdd);                    
                    this._reportIP(myScanHost.HostName);                   
                }                
                catch (Exception error)
                {                   
                    MessageBox.Show(error.Message); 
                }             
            }      
        }
gudicao 2012-12-23
  • 打赏
  • 举报
回复
可以详细点吗,直接调线程和调用辅助线程有什么区别吗?
Snowdust 2012-12-23
  • 打赏
  • 举报
回复
你这虽然用的是多线程,但都是从主线程调用的。你可以把任务放在辅线程中,只有在刷新界面的时候才在主线程调用。

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧