WinForm 多线程,高手请进!

wujinjian2008n 2008-12-30 01:33:54
我用C#窗体做了一个查询IP地址的程序(从数据库中查询),里面用了线程,但我每次点击搜索时,窗体就不能拖动了,过了一会儿窗体是可以拖动了,但一拖动程序就没有响应了。


为什么???
...全文
1729 85 打赏 收藏 转发到动态 举报
写回复
用AI写文章
85 条回复
切换为时间正序
请发表友善的回复…
发表回复
wujinjian2008n 2008-12-31
  • 打赏
  • 举报
回复
public void SearchThread()
{
for (int i = 0; i <= 100; i++)
{
this.Invoke((MethodInvoker)delegate
{

progressBar1.Value = i;
progressBar1.Refresh();

});
Thread.Sleep(100);
}
}

这样也可以的。只要将this.Invoke写在循环内就可以。那为什么不能写在循环外呢???高人解释一下!
wujinjian2008n 2008-12-31
  • 打赏
  • 举报
回复
anheizhizi,能详细说明一下流程吗??
wujinjian2008n 2008-12-31
  • 打赏
  • 举报
回复
[Quote=引用 68 楼 anheizhizi 的回复:]
this.Invoke内,此时一直是主线程在工作啊,你改成这样看下:


public Form1()
{
InitializeComponent();
progressBar1.Maximum = 100;
progressBar1.Minimum = 1;

}

private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(SearchThread));
t.Start();

[/Quote]

谢谢,非常感谢!

好复杂啊!
qiying1988 2008-12-31
  • 打赏
  • 举报
回复
up
CheekG 2008-12-31
  • 打赏
  • 举报
回复
70楼的代码,运行期间主窗体是不能拖动滴。。。。


public void SearchThread()
{
for (int i = 1; i < 100; i++)
{
this.Invoke(new Action <int>(show), i);
}
MessageBox.Show("Completed");

}

huangpeng8612 2008-12-31
  • 打赏
  • 举报
回复
不仔细看真看不出错误.
flyjimi 2008-12-31
  • 打赏
  • 举报
回复
[Quote=引用 63 楼 wujinjian2008n 的回复:]
谢谢各位!
问题简单一点,看如下代码,运行效果一样,一运行窗体就不能拖动,过了会儿能拖动了,但一拖动就死掉了!为什么??

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace SearchIp
{
public partial class Form1 : Form

[/Quote]

this.Invoke()是在UI线程执行。
你在Invoke()里面执行Thread.Sleep(100); 就是把UI线程休眠了。

public void SearchThread()
{
this.Invoke((MethodInvoker)delegate
{
for (int i = 0; i <= 364875; i++)
{
progressBar1.Value = i;
progressBar1.Refresh();

}
});
Thread.Sleep(100);
}
anheizhizi 2008-12-31
  • 打赏
  • 举报
回复
简单的说,就是将数据运算丢给子线程,真正写控件了才交给主线程。
anheizhizi 2008-12-31
  • 打赏
  • 举报
回复
this.Invoke内,此时一直是主线程在工作啊,你改成这样看下:


public Form1()
{
InitializeComponent();
progressBar1.Maximum = 100;
progressBar1.Minimum = 1;

}

private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(SearchThread));
t.Start();

}

public void SearchThread()
{
for (int i = 1; i < 100; i++)
{
this.Invoke(new Action<int>(show), i);
Thread.Sleep(100);
}

MessageBox.Show("Completed");

}

public void show(int i)
{
progressBar1.Value = i;
progressBar1.Refresh();
}

Maximum 的值我改成100了,你那个要等N久啊....
curtishang 2008-12-31
  • 打赏
  • 举报
回复
把Thread.Sleep 方法放到Invoke的外面
wujinjian2008n 2008-12-31
  • 打赏
  • 举报
回复
帮我看一下 63 楼代码的错误
window_8888 2008-12-31
  • 打赏
  • 举报
回复
呵....无解
Gavin_Y 2008-12-31
  • 打赏
  • 举报
回复
用多线称试试
wujinjian2008n 2008-12-31
  • 打赏
  • 举报
回复
谢谢各位!
问题简单一点,看如下代码,运行效果一样,一运行窗体就不能拖动,过了会儿能拖动了,但一拖动就死掉了!为什么??

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace SearchIp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(SearchThread));
t.Start();
}

private void Form1_Load(object sender, EventArgs e)
{
progressBar1.Maximum = 364875;
}

public void SearchThread()
{
this.Invoke((MethodInvoker)delegate
{
for (int i = 0; i <= 364875; i++)
{
progressBar1.Value = i;
progressBar1.Refresh();
Thread.Sleep(100);
}
});
}
}
}
wujinjian2008n 2008-12-31
  • 打赏
  • 举报
回复
谢谢各位!
问题简单一点,看如下代码,运行效果一样,一运行窗体就不能拖动,过了会儿能拖动了,但一拖动就死掉了!为什么??

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace SearchIp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(SearchThread));
t.Start();
}

private void Form1_Load(object sender, EventArgs e)
{
progressBar1.Maximum = 364875;
}

public void SearchThread()
{
this.Invoke((MethodInvoker)delegate
{
for (int i = 0; i <= 364875; i++)
{
progressBar1.Value = i;
progressBar1.Refresh();
Thread.Sleep(100);
}
});
}
}
}
wujinjian2008n 2008-12-31
  • 打赏
  • 举报
回复
谢谢各位
marvelstack 2008-12-31
  • 打赏
  • 举报
回复
可以通过异步模式来处理,简单一个可以使用BackgroundWorker组件来实现,如果时间长还可以提供进度显示,LZ可以参考一下这里,
http://blog.csdn.net/zhzuo/archive/2008/07/23/2699305.aspx
justindreams 2008-12-31
  • 打赏
  • 举报
回复
另外,我得指出一下大家的错误,大家都太关注Thread.Sleep了
其实罪魁祸首根本不是它,而是委托使用的方式(或者说,委托使用的位置)

委托很好用,但是千万不要滥用,特别是子线程里全用委托,那多线程就只是个花架子了,都交给主线程来做了,你的子线程还有什么存在的意义呢?那么多操作,那么长时间的操作,委托给主线程来操作,UI能不死吗?
所以,委托要用对了地方,取数运算等操作(包括线程休眠),这些一定要直接写在子线程里面,不要用委托,而子线程里对界面(UI)的操作,一定要(应该说不得不)使用委托,通知主线程来操作。另外,如果子线程里面如果有委托,如果不是必须,千万不要在委托里面加循环,一定要把循环放在委托外面。还有,复杂的界面操作,需要耗时的界面操作,不要放在一个委托里面,可以拆开放在几个委托来做。每个委托最好是要做最小的事情。
justindreams 2008-12-31
  • 打赏
  • 举报
回复
在Invoke里面写的东西都是委托给主线程来操作的,也就是UI线程来操作,你在Invoke里面用了循环,也就是相当于委托给主线程(也就是UI所在的线程)做循环,当然会不动了。
跟你讲一下子线程和委托应该怎么用:
使用子线程,本来就是为了不影响主线程的操作,所以,不要在子线程中把所有事情都委托给主线程来做,你看看你的方法,子线程里面,上来就开始用this.Invoke,而且子线程的操作都在委托里面,也就是相当于子线程的所有操作都委托给主线程来操作了,这样根本没有起到子线程的作用,而你需要做的是,只有界面的操作才用委托,其他的,都不要放在委托里面。

把程序给你改一下,我就不调试了,你自己试一下:注意看委托使用的位置,只有在


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.OleDb;
using System.Threading;

namespace SearchIp
{

public partial class Form1 : Form
{
private string ipStr;

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
label4.Text = "";
ipStr = textBox1.Text;

Thread t = new Thread(new ThreadStart(SearchThread));
t.Start();
}

private void Form1_Load(object sender, EventArgs e)
{
progressBar1.Maximum = 364875;
}

public void SearchThread()
{

string[] ipfd = ipStr.Split('.');

int ip1 = Convert.ToInt32(ipfd[0]);
int ip2 = Convert.ToInt32(ipfd[1]);
int ip3 = Convert.ToInt32(ipfd[2]);
int ip4 = Convert.ToInt32(ipfd[3]);

string sqlcmd="select * from IP_Address where IPStart like '%"+(ip1+"."+ip2)+"%'";
if(ip1 <12)
sqlcmd="select * from IP_Address where IPStart like '%"+ip1+"%'";

OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=IP.mdb");
con.Open();

OleDbCommand cmd = new OleDbCommand(sqlcmd, con);
OleDbDataReader dr = cmd.ExecuteReader();

while (dr.Read())
{
int ts = Convert.ToInt32(dr["Code"]);
this.Invoke((MethodInvoker)delegate
{
progressBar1.Value = ts;
progressBar1.Refresh();
label4.Text = ts + "";
label4.Refresh();
});

string[] IPS = dr["IPStart"].ToString().Split('.');
string[] IPE = dr["IPEnd"].ToString().Split('.');

int ips1 = Convert.ToInt32(IPS[0]);
int ips2 = Convert.ToInt32(IPS[1]);
int ips3 = Convert.ToInt32(IPS[2]);
int ips4 = Convert.ToInt32(IPS[3]);

int ipe1 = Convert.ToInt32(IPE[0]);
int ipe2 = Convert.ToInt32(IPE[1]);
int ipe3 = Convert.ToInt32(IPE[2]);
int ipe4 = Convert.ToInt32(IPE[3]);

if (ip1 >= ips1 && ip2 >= ips2 && ip3 >= ips3 && ip4 >= ips4 &&
ip1 <= ipe1 && ip2 <= ipe2 && ip3 <= ipe3 && ip4 <= ipe4)
{
this.Invoke((MethodInvoker)delegate
{
label2.Text = label2.Text + dr["IP_Address"].ToString();
});
break;
}

Thread.Sleep(2);
}
con.Close();
cmd.Dispose();
dr.Dispose();

}
}
}
anheizhizi 2008-12-31
  • 打赏
  • 举报
回复
借帖问星星个问题, 现在做一个WCF服务的负载测试工具,简单点说就是创建多个线程(100个以上)访问WCF,但实际使用中发现工具只开了2个端口发送请求,导致线程等待,网上也没找到详细的资料,不知道能否解答
加载更多回复(64)

111,120

社区成员

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

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

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