首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

多个线程操作DataGridView,怎么实现

2012-12-17 
多个线程操作DataGridView,如何实现?主程序从文件读取数据,每行开一个线程去处理,线程数nThreads不能大于n

多个线程操作DataGridView,如何实现?
主程序从文件读取数据,每行开一个线程去处理,线程数nThreads不能大于nMaxThreads,每个线程完成工作后,都要向DataGridView添加一行结果,用委托实现,结果是卡死.调试时,每个线程委托根本执行不到dataGridViewX1.Rows.Add(dgvr)这里来.请高手们指教啊!看哪里有问题,或是有其它好方法实现也行啊!


private int nMaxThreads, nThreads;
public delegate void CB_SetDataGridViewInfo(DataGridViewRow dgvr);
public void Deg_SetDataGridViewInfo(DataGridViewRow dgvr)//委托的方法
{
      if (this.dataGridViewX1.InvokeRequired)
      {
            CB_SetDataGridViewInfo cs = new CB_SetDataGridViewInfo(Deg_SetDataGridViewInfo);
            this.BeginInvoke(cs, new object[] { dgvr });
      }
      else
      {
            dataGridViewX1.Rows.Add(dgvr);
            dataGridViewX1.FirstDisplayedScrollingRowIndex = dataGridViewX1.Rows.Count;
      }
}
private void Thd_Start(object objPara)//线程
{
      do something.........//主要工作

      DataGridViewRow dgvr = new DataGridViewRow();
      dgvr.CreateCells(dataGridViewX1);
      for (int i = 0; i < 10; i++)
      {
           dgvr.Cells[i].Value = i;//这里是工作后的结果,用i临时代替一下
      }
      lock(this)
      {
           nThreads -= 1;//线程数减一
       }
       
      Deg_SetDataGridViewInfo(dgvr);// 托管调用
}
private void btxStart_Click(object sender, EventArgs e)
{
      if (tbxOpenFile.Text == null)
      {
            MessageBox.Show("请选择数据文件!");
            return;
      }
      string[] strLines = File.ReadAllLines(tbxOpenFile.Text, Encoding.Default);
      int nRows = strLines.Length;//总行数
      nMaxThreads = (int)nUDThread.Value;
      nThreads = 0;
      int nNow = 0;
      do
      {
          if (nThreads < nMaxThreads)//比较线程数有没有到最大限制
          {
               int nT = nMaxThreads - nThreads;
               for (int i = 0; i < nT; i++)
               {
                    string strLine = strLines[nNow + i];


                    Thread StartVerifyThread = new Thread(new ParameterizedThreadStart(Thd_StartVerify));
                    StartVerifyThread.IsBackground = true;
                    StartVerifyThread.Start(strLine);
               }

               lock (this)
               {
                    nNow += nT;
                    nThreads += nT;
               }
          }
     } while (nNow != nRows);//处理完所有数据行
}


[最优解释]
嗯,如果不用等待子线程,那就更好办了,你不是打开一个数据文件?那么,把数据文件的数据都读到一个表后直接使用匿名委托循环数据表赋值个控件列就好了,不用线程,这样写看起来很清楚明白也很爽.
线程最好处理与控件无关的数据操作或运算就好了.
那么,打开数据文件读取数据到一个表就可以用线程去处理,之后就可以写一个方法,把数据表作为参数传递个方法用委托去处理.
这里就是表赋值到控件参考
[其他解释]
真心搞不懂楼主为什么要把简单的问题复杂化。从代码看来,楼主似乎要处理一个很大的文本文件,然后把处理结果实时在DataGridView里体现,说说我的几点想法。
1、如果文本文件很大,用ReadAllLines这个方法很不合适,它会一次性把文件里的内容加载到内存里,内存的消耗一定很大。
2、每个线程只处理一行文本,太浪费系统资源,要知道线程的创建和销毁也是要有开销的。
3、直接对Rows集合操作可能不是一个很好的办法,参考Windows 窗体 DataGridView 控件中的性能优化。
建议做以下修改:
1、使用1个额外的线程读取文件内容。
2、在这个线程中,使用流方式读取文本文件,如有必要可以自己派生一个TextReader类。
3、使用BindingSource。
[其他解释]
不要在线程中操作界面,正确的做法是调用Control.Invoke,并且将操作的代码作为委托传进去,让界面自己处理。
[其他解释]
引用:
private void Thd_Start(object objPara)//线程
{
      do something.........//主要工作
 
      DataGridViewRow dgvr = new DataGridViewRow();
      dgvr.CreateCells(dataGridViewX1);
      for (int i = 0; i < 10; i++)
      {
           dgvr.Cells[i].Value = i;//这里是工作后的结果,用i临时代替一下
      }
      lock(this)
      {
           nThreads -= 1;//线程数减一
       }
        
      Deg_SetDataGridViewInfo(dgvr);// 托管调用
这个方法执行时你的系统不会崩溃吗?你使用什么.net版本?在2.0以上都是需要 Control.Invoke 来操作。
[其他解释]
这代码不是很好改动,有点手工造轮子的弄法

现代coder,已经不在这么玩了。
1.线程池自己就能管控,用不着你这么绕来绕去
2.UI是UI,数据是数据。你只对数据操作就ok,利用双向数据绑定对象,线程上下文同步对象,简单几步就ok了
[其他解释]


int[] a = new int[10];
for (int i = 0; i < 10; i++)      

       a[i]=i;     
 } 

gridView1.DataSource = a;
[其他解释]
首先表示看不太懂这种写法,其实委托可以采用雷姆达表达式或匿名实现看起来也很爽.
其二线程可以采用等待方法:线程.Join();就够用了,锁很少用到,同样可以实现.
其三不需要没行开一个线程,可以创建一个数据表,操作数据表后帮定个显示数据控件,当然也可以直接操作数据显示控件,这看个人的了.
关于Excel操作编写的一个软件设计构思案例[连载]这篇里面就采用有操作数据表和控件的方法
这里有委托和线程更容易的方法参考
[其他解释]

引用:
首先表示看不太懂这种写法,其实委托可以采用雷姆达表达式或匿名实现看起来也很爽.
其二线程可以采用等待方法:线程.Join();就够用了,锁很少用到,同样可以实现.
其三不需要没行开一个线程,可以创建一个数据表,操作数据表后帮定个显示数据控件,当然也可以直接操作数据显示控件,这看个人的了.
关于Excel操作编写的一个软件设计构思案例[连载]这篇里面就采用有操作数据表和控件的方法
这里有委托……


不都是这样用委托的吗?
其二,我主线程是不用等待子线程的,子线程是去处理网络行为的,如每个数据行是个IP地址,子线程去ping,返回的结果显示出来.
[其他解释]
引用:
不要在线程中操作界面,正确的做法是调用Control.Invoke,并且将操作的代码作为委托传进去,让界面自己处理。

我不就是在线程里用委托吗!Deg_SetDataGridViewInfo(dgvr);
[其他解释]
private void Thd_Start(object objPara)//线程 
这里写错了!应该是
private void Thd_StartVerify(object objPara)//线程 
[其他解释]
哦,看到了你写了
this.BeginInvoke(.....)

你的代码可真够繁琐曲折的。
[其他解释]
看不懂啊,这是什么意思?
      lock(this)
      {
           nThreads -= 1;//线程数减一
       }

[其他解释]
该回复于2012-11-25 12:47:10被管理员删除
[其他解释]
如果用匿名委托的话只要一个方法就够了,如:
按钮事件:读数据到数组string[],循环数组调用数据处理方法,把参数传递过去。
处理数据方法:线程处理接收回来数据,匿名委托数据赋值给控件。注意我这里说的是把线程写在方法里,而不是写在事件中。
你的那种写法我看得晕,还有你说的不用管线程处理也有问题,如果不管那么锁什么呢?如果你说不用管显示出来的数据快慢还差不多,把主次弄清楚了再设计。
21.private void 读文本(string 文件名称, string 比较内容)  
{  
    List<string> 内容 = new List<string>(); bool 控制 = true;  
    if (Directory.Exists(保存路径))  
    {  
        FileInfo 文件 = new FileInfo(文件名);  
        if (文件.Exists)  
        {  
            using (FileStream 打开 = new FileStream(文件名, FileMode.Open))  
            {  
                using (StreamReader 读取 = new StreamReader(打开, Encoding.UTF8))  
                {  
                    while (!读取.EndOfStream)  


                    {  
                        if (比较内容 == "") 内容.Add(读取.ReadLine());  
                        else  
                            if (比较内容 == 读取.ReadLine()) { 控制 = false; break; }  
                    }  
                    打开.Close(); if (控制) 记录文本(比较内容, 文件名称);  
                }  
            }  
        }  
    }  
    foreach (string 数据 in 内容) if (数据.Contains("☆")) { 补缺地址(数据); }  
}  


就好像这个方法一样读数据到数组,然后传递给方法去处理,再如如下方法就是使用线程和委托当然这里只是举例而已:

private void 时间_Tick(object sender, EventArgs e)
 {
 Thread 线程 = new Thread(delegate()
 {
 if (秒 < 59) 秒++; else { 秒 = 0; 分++; } if (分 == 60) { 分 = 0; 时++; } if (时 == 5) 时 = 0;
 this.Invoke(new Action(() =>
显示时间.Text = DateTime.Parse(时.ToString("0:") + 分.ToString("00:") + 秒.ToString("00")).ToLongTimeString()));
 }); 线程.Start();
 }


[其他解释]
再则操作控件写法:
for (int 列 = 2; 列 < 5; 列++) 处理结果.Rows[行].Cells[列 + 1].Value = 字符[列];  
这样更小葱拌豆腐不是?
[其他解释]
想我在初学时多听不同意见,多调试很多人不同代码从中学习,所以能掌握相同功能不同写法实现,做到写代码游刃有余,随心所欲,无所挂碍,这可是我得益心得.
[其他解释]
引用:
看不懂啊,这是什么意思?


C# code?



1234

      lock(this)       {            nThreads -= 1;//线程数减一        }

就是每一个线程执行完后,线程数减一,然后主线程可以根据全局的判断线程数不够最大了,可以再开线程.
[其他解释]
引用:
想我在初学时多听不同意见,多调试很多人不同代码从中学习,所以能掌握相同功能不同写法实现,做到写代码游刃有余,随心所欲,无所挂碍,这可是我得益心得.
嗯,说得是
[其他解释]
引用:
这代码不是很好改动,有点手工造轮子的弄法

现代coder,已经不在这么玩了。
1.线程池自己就能管控,用不着你这么绕来绕去
2.UI是UI,数据是数据。你只对数据操作就ok,利用双向数据绑定对象,线程上下文同步对象,简单几步就ok了
本来我的方法感觉就是比较繁琐,想请教更好的方法.
那可不可以按你说的方法就是数据绑定呢?


比如说,我线程去操作数据表,数据表绑定到datagridview.线程上下文同步.试试吧!
[其他解释]
如果文件不大干嘛要搞得那么复杂啊,不是找抽嘛。
要使用BindingSource,你得先有一个模型类,可以把文件中的列映射到类的属性里。在设计器里将DataGridView的DataSource属性指定为这个类型,设计器就会自动为你添加一个相应的BindingSource组件,而在程序里只需要往BidingSource里添加内容即可。详细的使用方便参考MSDN。
[其他解释]

引用:
真心搞不懂楼主为什么要把简单的问题复杂化。从代码看来,楼主似乎要处理一个很大的文本文件,然后把处理结果实时在DataGridView里体现,说说我的几点想法。
1、如果文本文件很大,用ReadAllLines这个方法很不合适,它会一次性把文件里的内容加载到内存里,内存的消耗一定很大。
2、每个线程只处理一行文本,太浪费系统资源,要知道线程的创建和销毁也是要有开销的。
3、直接对Rows集合操……
我的文件一般不会很大,是一些IP地址列表.
BindingSource怎么实现?
[其他解释]
就用单线程吧
[其他解释]
UI控件相对于不同的线程来说是共享资源,UI控件本身操作的时候不是线程安全的,也就是没有锁,你多个线程直接操作一个不加锁的共享资源你觉得可以吗? 很多方法可以实现,好比上面说的control.invoke,或者用sendmessage发消息通知UI现成修改UI也可以。
[其他解释]
引用:
引用:
就用单线程吧就是因为单线程比较慢啊,如果数据有几十万行,每行处理起来要十几秒的话,不是很慢


虽然你使用了多个线程,但是每个线程都访问同一个控件,由于UI线程只能允许一个线程访问,所以你一个线程在访问grid的时候,其他线程是挂起等待状态,所以还是单线程,并且比以前更慢,因为有线程切换的时间。如果要多线程,应该是多线程处理数据,处理完后在给grid的datasource赋值就行了.如果一次绑定100万条会慢,最好的方法是可以让grid一次只绑定10000条,当客户下拉滚动条的时候动态加载.
[其他解释]
引用:
就用单线程吧
就是因为单线程比较慢啊,如果数据有几十万行,每行处理起来要十几秒的话,不是很慢
[其他解释]
引用:
引用:
引用:
就用单线程吧就是因为单线程比较慢啊,如果数据有几十万行,每行处理起来要十几秒的话,不是很慢

虽然你使用了多个线程,但是每个线程都访问同一个控件,由于UI线程只能允许一个线程访问,所以你一个线程在访问grid的时候,其他线程是挂起等待状态,所以还是单线程,并且比以前更慢,因为有线程切换的时间。如……
具体怎么个绑定法,能给伪代码吗?多谢了,本人菜鸟!
[其他解释]
引用:
引用:就用单线程吧就是因为单线程比较慢啊,如果数据有几十万行,每行处理起来要十几秒的话,不是很慢


1行十几秒是什么概念?我做过一个CCProxy日志分析软件,每秒可以分析几千行,也只用了一个线程。
[其他解释]

DataTable dt = new DataTable();
            dt.Columns.Add("Name");
            for (int i = 0; i < 10; i++)
            {
                dt.Rows.Add(i);
            }
            dataGridView1.DataSource = dt;

[其他解释]
搞定了,原来的代码是有问题的.这里
      
do      
{           
    if (nThreads < nMaxThreads)//比较线程数有没有到最大限制           
    {                
        int nT = nMaxThreads - nThreads;                


        for (int i = 0; i < nT; i++)                
        {                     
             string strLine = strLines[nNow + i];
             Thread StartVerifyThread = new Thread(new ParameterizedThreadStart(Thd_StartVerify));
             StartVerifyThread.IsBackground = true;
             StartVerifyThread.Start(strLine);
        }                  
        lock (this)                
        {                     
            nNow += nT;                     
            nThreads += nT;                
        }           
    }      
} while (nNow != nRows);//处理完所有数据行 


这样起线程方式有合理,现在改成线程数固定,每个线程处理多行数据.再用委托就没问题了!
[其他解释]
亲,用委托吧,DataGridView在UI线程中可以操作,在线程中使用回调。
[其他解释]
说错了,"不合理"

热点排行