关于线程操作datagridview的问题,100分求正解,立即给分! 本帖最后由 GUNDAM525 于 2010-01-07 12:39:30 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 private void SetDataGridView() //控件操作 { lock (this) { DataViewsSet = oraCls.createView(dateTimePicker1.Value.ToString("yyyyMMdd"), dateTimePicker2.Value.ToString("yyyyMMdd"), myFilter());//, bindingNavigator1); DataViews.AutoGenerateColumns = true; DataViews.DataSource = DataViewsSet.Tables[0]; for (int i = 0; i < DataViews.Columns.Count; i++) { DataViews.Columns[i].HeaderCell.Style.WrapMode = DataGridViewTriState.False; } //将字段名写入listBox for (int j = 0; j < DataViews.ColumnCount; j++) LstBx_All.Items.Add(DataViews.Columns[j].Name); DataViews.Refresh(); LB_Count.Text = "记录数:" + (DataViews.RowCount - 1).ToString(); }} 你这线程跟没用一样,这里的委托里的代码是和form主线程同步的,要在线程里循环 是吧,我对线程还没有太多的了解,但是客户要求查询数据时datagridview不要在那里假死把整个程序给卡着动不了。实际上,我这段代码主要的是 DataViewsSet = oraCls.createView(dateTimePicker1.Value.ToString("yyyyMMdd"),dateTimePicker2.Value.ToString("yyyyMMdd"), myFilter DataViews.AutoGenerateColumns = true; DataViews.DataSource = DataViewsSet.Tables[0]; for (int i = 0; i < DataViews.Columns.Count; i++) { DataViews.Columns[i].HeaderCell.Style.WrapMode = DataGridViewTriState.False; } //将字段名写入listBox for (int j = 0; j < DataViews.ColumnCount; j++) LstBx_All.Items.Add(DataViews.Columns[j].Name); DataViews.Refresh(); LB_Count.Text = "记录数:" + (DataViews.RowCount - 1).ToString(); 就是用datatable把数据库中的数据取出来放在grid里面,请问该如何做呢 帮你简单改了下 把多线程改成异步 你自己测试看看#region 用多线程测试 delegate void SetVisibleDelegate(); Thread DataViewsThread; DataSet DataViewsSet = new DataSet(); //private void BindThread() //{ // //Control.CheckForIllegalCrossThreadCalls = false; // ThreadStart bind = new ThreadStart(SetDataGridView); // DataViewsThread = new Thread(bind); // DataViewsThread.Start(); //} private void CheckIsIn() { SetVisibleDelegate mDelegate = new SetVisibleDelegate(()=>{DataViewsSet = oraCls.createView(dateTimePicker1.Value.ToString("yyyyMMdd"), dateTimePicker2.Value.ToString("yyyyMMdd"), myFilter());}); mDelegate.BeginInvoke(CallBack, null); } private void CallBack(IAsyncResult ar) { if (ar == null) return; if (ar.IsCompleted) { if (this.InvokeRequired) { MethodInvoker mInvoker = new MethodInvoker(SetDataGridView); this.Invoke(mInvoker, null); } else { SetDataGridView(); } } } private void SetDataGridView() //控件操作 { //DataViewsSet = oraCls.createView(dateTimePicker1.Value.ToString("yyyyMMdd"), dateTimePicker2.Value.ToString("yyyyMMdd"), myFilter());//, bindingNavigator1); DataViews.AutoGenerateColumns = true; DataViews.DataSource = DataViewsSet.Tables[0]; for (int i = 0; i < DataViews.Columns.Count; i++) { DataViews.Columns[i].HeaderCell.Style.WrapMode = DataGridViewTriState.False; } //将字段名写入listBox for (int j = 0; j < DataViews.ColumnCount; j++) LstBx_All.Items.Add(DataViews.Columns[j].Name); DataViews.Refresh(); LB_Count.Text = "记录数:" + (DataViews.RowCount - 1).ToString(); }#endregion 谢谢,但是还是卡着不动了,我怀疑是不是datagridview自身对大量数据显示处理的问题,有没有办法让数据滚动式添加到datagridview中去呢?由于取出数据量稍微有点大,用户也知道他要查询的数据很多,需要时间处理,就是不能忍受界面卡着不动,呵呵 另外加个滚动条?已经在datagridview中设置了啊,scollbar=both,还要另外加一个? 显示的问题 你试试DataGridView虚拟模式虚拟模式是为使用大型数据存储区而设计的。当 VirtualMode 属性为 true 时,可以创建一个包含大量行和列的 DataGridView,然后处理 CellValueNeeded 事件来填充单元格。虚拟模式要求实现基础数据缓存,以便基于用户的操作来处理 DataGridView 单元格的填充、编辑和删除。(MSDN) 我遇到的情况跟你很相似,我的情况:1.主界面一开始运行就开启一个线程TempThread ,时刻监听本机端口(2000)收到的数据 2.将数据转化翻译后,添加到DataGridView的列表里面 3.由于我监听的是所有消防联网用户往监控中心上报的报警信息,数据很多 4.出现的问题,我的DataGridView能一次显示30条信息,但是,一过30条,滚动条就假死, 还不能去拉动滚动条,否则,整个程序会变成 未响应问题的已经解决。由于程序本身是一个线程,监听是一个线程,而线程之间的控件赋值就会报错,所以采用委托的办法解决。但是,我如楼主一样,之前的委托使得不对,滚动条照样假死。后来改成: #region 构造函数 public MainFrm() { InitializeComponent(); ThreadStart TS = new ThreadStart(this.StartReceive);//端口监听线程 Thread TempThread = new Thread(TS); TempThread.IsBackground = true;//后台运行 TempThread.Start(); } #endregion private void StartReceive()//端口监听线程 { TcpListener server = new TcpListener(IPAddress.Parse(Operator.ServerIP),2000); server.Start();//监听本机2000端口,收取报告 MethodInvoker mi = new MethodInvoker(Add_Alarm);//声明委托,即往DataGridView添加行 while (true) { TcpClient client = server.AcceptTcpClient(); NetworkStream ns = client.GetStream(); byte[] bytes = new byte[1024]; int bytesread = ns.Read(bytes, 0, bytes.Length); msg = Encoding.Default.GetString(bytes, 0, bytesread);//监听到的数据 if (msg != "") { Common.SysRun_Log(Operator.RunLogFpath, "系统监听到 " + msg);//运行日志 this.BeginInvoke(mi);//执行委托 } ns.Close(); client.Close(); } } private void Add_Alarm() //将监听到的火警报告插入 DataGridView { msg = MainFrmB.Add_AlarmInfo(msg); Common.SysRun_Log(Operator.RunLogFpath, "消息格式化后 " + msg); //运行日志 msg = msg.Insert(msg.LastIndexOf('|') + 1, "火警 "); this.dataGridView1.Rows.Insert(0, msg.Split('|'));//插入一行新的报告 dataGridView1.Rows[0].DefaultCellStyle.BackColor = Color.Red; }希望能够帮到你 你的说虚拟模式我也看过了,但是我还没有明白cellvalueneeded事件填充单元格到底是如何实现的,看了例子没太明白这个事件是怎么回事 MethodInvoker mi = new MethodInvoker(Add_Alarm);//声明委托,即往DataGridView添加行 我是采用c# winform 中MethodInvoker 委托类来处理我要操作控件的过程 操作控件的过程都封装在Add_Alarm函数里面 谢谢,但是按照你的写法,datagridview在从datatable取值过程中,程序还是会假死。呵呵,我那个写法,至少在执行过程中,程序可以自由活动,只是到数据出来后,滚动条不能用罢了 这是我按照你的写法改的代码,但是执行时,界面仍会卡,我想是不是我数据太多,需要在datatable里做点处理啊 private void BTN_Login_Click(object sender, EventArgs e) { LB_Count.Text = "正在查询数据库……"; DataViews.Columns.Clear(); DataViews.Visible = true;//这个是我当前显示产品数据的grid PDSDataView.Visible = false; //一次只让一个grid显示在用户上 FailCoilDataView.Visible = false;//这个和上面PDSDataView是用来做废品判断显示 ThreadStart TS = new ThreadStart(this.ControlGrid); Thread TempThread = new Thread(TS); TempThread.IsBackground = true;//后台运行 TempThread.Start(); for (int i = 0; i < DataViews.Columns.Count; i++) { DataViews.Columns[i].HeaderCell.Style.WrapMode = DataGridViewTriState.False; } //将字段名写入listBox for (int j = 0; j < DataViews.ColumnCount; j++) LstBx_All.Items.Add(DataViews.Columns[j].Name); }private void ControlGrid() { MethodInvoker mi = new MethodInvoker(SetDataGridView);//声明委托,即往DataGridView添加行 this.BeginInvoke(mi); } private void SetDataGridView() //控件操作 { DataSet DataViewsSet = new DataSet(); DataViewsSet = oraCls.createView(dateTimePicker1.Value.ToString("yyyyMMdd"), dateTimePicker2.Value.ToString("yyyyMMdd"), myFilter()); DataViews.DataSource = DataViewsSet.Tables[0]; LB_Count.Text = "记录数:" + (DataViews.RowCount - 1).ToString(); } 能不能把 BTN_Login_Click(object sender, EventArgs e)中的 for (int i = 0; i < DataViews.Columns.Count; i++) { DataViews.Columns[i].HeaderCell.Style.WrapMode = DataGridViewTriState.False; } //将字段名写入listBox for (int j = 0; j < DataViews.ColumnCount; j++) LstBx_All.Items.Add(DataViews.Columns[j].Name); 剪切到 SetDataGridView() 的开头去,因为上面两段代码都是跨线程操作控件赋值, 但这样修改后,不知是否会影响你的业务逻辑 private void DataViews_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { e.Value = DataViewsSet.Tables[0].Rows[e.RowIndex][e.ColumnIndex]; } 估计你的问题不在这里 我刚测试 4000行300列 所有cell值为26个字母 用DataSource绑定 显示很快毙掉DataViews.Refresh(); 试试 用C#写QQ农场外挂 谁能帮下转下代码(C++转C#),WINCE下的SendMessage 新手要想一个WINFORM的小系统 新手,求一段简单正则表达式 请教变自定义控件高手 网页之间传对象怎么传? 请问我的dataRow里为什么是空呢? 语言学习太闷了,就开始有点意思,现在好累 c#如何切换主显示器有可以使用的API吗? wpf listview使用求助,获取选中行,第三列的数据。 如何批量生成字符???? 英语翻译view student wise and date wise attendance
{ lock (this)
{ DataViewsSet = oraCls.createView(dateTimePicker1.Value.ToString("yyyyMMdd"), dateTimePicker2.Value.ToString("yyyyMMdd"), myFilter());//, bindingNavigator1); DataViews.AutoGenerateColumns = true;
DataViews.DataSource = DataViewsSet.Tables[0];
for (int i = 0; i < DataViews.Columns.Count; i++)
{
DataViews.Columns[i].HeaderCell.Style.WrapMode = DataGridViewTriState.False;
} //将字段名写入listBox
for (int j = 0; j < DataViews.ColumnCount; j++)
LstBx_All.Items.Add(DataViews.Columns[j].Name); DataViews.Refresh();
LB_Count.Text = "记录数:" + (DataViews.RowCount - 1).ToString();
}
}
实际上,我这段代码主要的是 DataViewsSet = oraCls.createView(dateTimePicker1.Value.ToString("yyyyMMdd"),dateTimePicker2.Value.ToString("yyyyMMdd"), myFilter
DataViews.AutoGenerateColumns = true;
DataViews.DataSource = DataViewsSet.Tables[0]; for (int i = 0; i < DataViews.Columns.Count; i++)
{
DataViews.Columns[i].HeaderCell.Style.WrapMode = DataGridViewTriState.False;
} //将字段名写入listBox
for (int j = 0; j < DataViews.ColumnCount; j++)
LstBx_All.Items.Add(DataViews.Columns[j].Name); DataViews.Refresh();
LB_Count.Text = "记录数:" + (DataViews.RowCount - 1).ToString();
就是用datatable把数据库中的数据取出来放在grid里面,请问该如何做呢
你自己测试看看#region 用多线程测试
delegate void SetVisibleDelegate();
Thread DataViewsThread;
DataSet DataViewsSet = new DataSet();
//private void BindThread()
//{
// //Control.CheckForIllegalCrossThreadCalls = false;
// ThreadStart bind = new ThreadStart(SetDataGridView);
// DataViewsThread = new Thread(bind);
// DataViewsThread.Start();
//} private void CheckIsIn()
{
SetVisibleDelegate mDelegate = new SetVisibleDelegate(()=>{DataViewsSet = oraCls.createView(dateTimePicker1.Value.ToString("yyyyMMdd"), dateTimePicker2.Value.ToString("yyyyMMdd"), myFilter());});
mDelegate.BeginInvoke(CallBack, null);
} private void CallBack(IAsyncResult ar)
{
if (ar == null)
return;
if (ar.IsCompleted)
{
if (this.InvokeRequired)
{
MethodInvoker mInvoker = new MethodInvoker(SetDataGridView);
this.Invoke(mInvoker, null);
}
else
{
SetDataGridView();
}
}
}
private void SetDataGridView() //控件操作
{ //DataViewsSet = oraCls.createView(dateTimePicker1.Value.ToString("yyyyMMdd"), dateTimePicker2.Value.ToString("yyyyMMdd"), myFilter());//, bindingNavigator1); DataViews.AutoGenerateColumns = true;
DataViews.DataSource = DataViewsSet.Tables[0];
for (int i = 0; i < DataViews.Columns.Count; i++)
{
DataViews.Columns[i].HeaderCell.Style.WrapMode = DataGridViewTriState.False;
} //将字段名写入listBox
for (int j = 0; j < DataViews.ColumnCount; j++)
LstBx_All.Items.Add(DataViews.Columns[j].Name); DataViews.Refresh();
LB_Count.Text = "记录数:" + (DataViews.RowCount - 1).ToString(); }
#endregion
2.将数据转化翻译后,添加到DataGridView的列表里面
3.由于我监听的是所有消防联网用户往监控中心上报的报警信息,数据很多
4.出现的问题,我的DataGridView能一次显示30条信息,但是,一过30条,滚动条就假死,
还不能去拉动滚动条,否则,整个程序会变成 未响应问题的已经解决。由于程序本身是一个线程,监听是一个线程,而线程之间的控件赋值就会报错,所以采用
委托的办法解决。但是,我如楼主一样,之前的委托使得不对,滚动条照样假死。后来改成: #region 构造函数
public MainFrm()
{
InitializeComponent();
ThreadStart TS = new ThreadStart(this.StartReceive);//端口监听线程
Thread TempThread = new Thread(TS);
TempThread.IsBackground = true;//后台运行
TempThread.Start();
}
#endregion private void StartReceive()//端口监听线程
{
TcpListener server = new TcpListener(IPAddress.Parse(Operator.ServerIP),2000);
server.Start();//监听本机2000端口,收取报告
MethodInvoker mi = new MethodInvoker(Add_Alarm);//声明委托,即往DataGridView添加行
while (true)
{
TcpClient client = server.AcceptTcpClient();
NetworkStream ns = client.GetStream();
byte[] bytes = new byte[1024];
int bytesread = ns.Read(bytes, 0, bytes.Length);
msg = Encoding.Default.GetString(bytes, 0, bytesread);//监听到的数据
if (msg != "")
{
Common.SysRun_Log(Operator.RunLogFpath, "系统监听到 " + msg);//运行日志
this.BeginInvoke(mi);//执行委托
}
ns.Close();
client.Close();
}
}
private void Add_Alarm() //将监听到的火警报告插入 DataGridView
{
msg = MainFrmB.Add_AlarmInfo(msg);
Common.SysRun_Log(Operator.RunLogFpath, "消息格式化后 " + msg); //运行日志
msg = msg.Insert(msg.LastIndexOf('|') + 1, "火警 ");
this.dataGridView1.Rows.Insert(0, msg.Split('|'));//插入一行新的报告
dataGridView1.Rows[0].DefaultCellStyle.BackColor = Color.Red;
}希望能够帮到你
操作控件的过程都封装在Add_Alarm函数里面
{
LB_Count.Text = "正在查询数据库……";
DataViews.Columns.Clear();
DataViews.Visible = true;//这个是我当前显示产品数据的grid
PDSDataView.Visible = false; //一次只让一个grid显示在用户上
FailCoilDataView.Visible = false;//这个和上面PDSDataView是用来做废品判断显示
ThreadStart TS = new ThreadStart(this.ControlGrid);
Thread TempThread = new Thread(TS);
TempThread.IsBackground = true;//后台运行
TempThread.Start(); for (int i = 0; i < DataViews.Columns.Count; i++)
{
DataViews.Columns[i].HeaderCell.Style.WrapMode = DataGridViewTriState.False;
} //将字段名写入listBox
for (int j = 0; j < DataViews.ColumnCount; j++)
LstBx_All.Items.Add(DataViews.Columns[j].Name);
}private void ControlGrid()
{
MethodInvoker mi = new MethodInvoker(SetDataGridView);//声明委托,即往DataGridView添加行
this.BeginInvoke(mi);
}
private void SetDataGridView() //控件操作
{
DataSet DataViewsSet = new DataSet();
DataViewsSet = oraCls.createView(dateTimePicker1.Value.ToString("yyyyMMdd"), dateTimePicker2.Value.ToString("yyyyMMdd"), myFilter()); DataViews.DataSource = DataViewsSet.Tables[0]; LB_Count.Text = "记录数:" + (DataViews.RowCount - 1).ToString();
}
{
DataViews.Columns[i].HeaderCell.Style.WrapMode = DataGridViewTriState.False;
} //将字段名写入listBox
for (int j = 0; j < DataViews.ColumnCount; j++)
LstBx_All.Items.Add(DataViews.Columns[j].Name);
剪切到 SetDataGridView() 的开头去,因为上面两段代码都是跨线程操作控件赋值,
但这样修改后,不知是否会影响你的业务逻辑
private void DataViews_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
e.Value = DataViewsSet.Tables[0].Rows[e.RowIndex][e.ColumnIndex];
}
毙掉DataViews.Refresh(); 试试