最近边写一个程序,数据库更新比较慢,所以单开了一个线程,主线程里有个while循环,用来不断刷新进度条显示更新到哪一条。程序不和用户交互没有问题,但是只要用户切换一下窗口,也就是进度条窗口失去焦点,在激活窗体后进度条和text就不刷新了不知道是什么问题,不是两个线程么,为什么切换一下窗口就暂停refresh了?怎么办才能办到切换也刷新啊?小白请大大赐教~

解决方案 »

  1.   

    1、你的线程在显示当前的进度,也就是写text属性和设置进度条的代码,要以委托来执行。
    2、建议你降低线程的级别为belownormal。
      

  2.   

    根本原因在于while的循环不止,造成不能及时刷新进度条,所以如果没有执行完时,看似进度条停止了,一旦执行完成,你会发现进度条马上变到100%.
    建议用计器timer,在它的Tick事件中执行更新进度条的代码,只要设置一个适当的时间间隔interval即可。
    或者把更新进度条的代码也写在一个线程中,但可能会发生“线程间操作无效:”错误,可以在初始化时或load事件中写上这一句:Control.CheckForIllegalCrossThreadCalls = false;
      

  3.   

    更新数据库的线程代码:
    private void UpdateProgress()
            {
                string AllUpCommString = "Select 代码,名称 from stockSelect";
                string StockID, StockName;
                SqlConnection ConnNew = new SqlConnection(Constant.ConnStock);
                SqlCommand AllUpCmd = new SqlCommand(AllUpCommString, ConnNew);
                ConnNew.Open();
                SqlDataReader MyDataReader = AllUpCmd.ExecuteReader();            while (MyDataReader.Read())
                {
                    StockID = (string)MyDataReader[0];
                    StockName = (string)MyDataReader[1];
                    UpdateStock(StockID);
                    lock ((object) PStruct)
                    {
                        PStruct.ProgressStock = "正在更新" + StockName + "(" + StockID + ")";
                        PStruct.ProgressSum++;
                    }
                    UpdateAllThread.Suspend();
                    //if (StockID == "000007")
                    //    break;
                }                   }更新进度条部分的代码(主线程):
    private void 全部股票更新ToolStripMenuItem_Click(object sender, EventArgs e)
            {
                AllStockUpdate AllUD = new AllStockUpdate();
                AllUD.Text = "更新所有股票";
                AllUD.label1.Text = "正在更新";            AllUD.Tmp = UpdateAllThread;            AllUD.Show();
                AllUD.progressBar1.Show();
                Application.DoEvents();
                AllUD.progressBar1.Maximum = TotalStockNum;
                AllUD.progressBar1.Minimum = 0;
                AllUD.progressBar1.Step = 1;            UpdateAllThread = new Thread(new ThreadStart(UpdateProgress));
                UpdateAllThread.Priority = ThreadPriority.BelowNormal;
                UpdateAllThread.Start();
                while (PStruct.ProgressSum <= TotalStockNum)
                {
                    AllUD.Refresh();
                    if(UpdateAllThread.ThreadState == ThreadState.Suspended||UpdateAllThread.ThreadState == ThreadState.SuspendRequested)
                    {
                        lock ((object)PStruct)
                        {                        AllUD.progressBar1.Value = PStruct.ProgressSum;
                            AllUD.label1.Text = PStruct.ProgressStock;
                        }
                        //AllUD.Refresh();
                        UpdateAllThread.Resume();
                        MyDataGridView.Refresh();
                        menuStrip1.Refresh();
                    }
                    if(UpdateAllThread.ThreadState == ThreadState.Stopped)
                        break;
                    //Thread.Sleep(10);
                }
                AllUD.Hide();            String SqlCmdNew = "select NUM,代码,名称,综合指数,更新日期,现价,港股价格,溢价率 from stockSelect";
                SqlCommand MySqlCommNew = new SqlCommand(SqlCmdNew, Conn);
                SqlDataAdapter MyDataAdNew = new SqlDataAdapter(MySqlCommNew);
                MyDataSet.Clear();
                MyDataAdNew.Fill(MyDataSet, "StockInfo");
                this.MyDataGridView.DataSource = MyDataSet.Tables["StockInfo"];
                MyDataGridView.Columns[0].Visible = false;
                Conn.Close();            AllUD.Dispose();
            }
      

  4.   


    可是我的while 循环是用来刷新进度条的refresh()啊,怎么还能把刷新的过程给停止了?而且我发现我进度条那个窗口的控件都不能响应,任何按钮很是困惑啊。。
      

  5.   


                while (PStruct.ProgressSum <= TotalStockNum) 
                { 
                    AllUD.Refresh(); 
                    if(UpdateAllThread.ThreadState == ThreadState.Suspended||UpdateAllThread.ThreadState == ThreadState.SuspendRequested) 
                    { 
                        lock ((object)PStruct) 
                        {                         AllUD.progressBar1.Value = PStruct.ProgressSum; 
                            AllUD.label1.Text = PStruct.ProgressStock; 
                        } 
                        //AllUD.Refresh(); 
                        UpdateAllThread.Resume(); 
                        MyDataGridView.Refresh(); 
                        menuStrip1.Refresh(); 
                    } 
                    if(UpdateAllThread.ThreadState == ThreadState.Stopped) 
                        break; 
                    //Thread.Sleep(10); 
                } 
    //感觉问题应该在这里,因为你只判断了线程的三种状态,其实线程状态还有很多其实三楼的建议不错,应该将刷新进度条放在一个单独线程中或采用定时器Timer完成
      

  6.   

    你的线程是窗体的辅线程
    辅线程运行会自动阻塞主线程
    怎么办吧,就要辅线程有机会给主线程执行
    doevent或SLEEP
      

  7.   

    lz在“全部股票更新ToolStripMenuItem_Click”方法中的while循环可能是想循环监控存储进度的结构体PStruct的值,以达到同步显示的目的。我的建议:
    lz在UpdateProgress()方法中就可以用委托来刷新显示进度条的显示。delegate void dlt_CallProgress(string strText,int intProgress);
    dlt_CallProgress Invoke_CallProgress;void CallProgress(string strText,int intProgress)
    {
         AllUD.progressBar1.Value = strText; 
         AllUD.label1.Text = intProgress;
    }
    然后
    在UpdateProgress()方法的while循环中
                while (MyDataReader.Read())
                {
                    StockID = (string)MyDataReader[0];
                    StockName = (string)MyDataReader[1];
                    UpdateStock(StockID);
                    lock ((object) PStruct)
                    {
                        PStruct.ProgressStock = "正在更新" + StockName + "(" + StockID + ")";
                        PStruct.ProgressSum++;
                    }
                    UpdateAllThread.Suspend();
                    //if (StockID == "000007")
                    //    break;
                }
    改动为
                while (MyDataReader.Read())
                {
                    StockID = (string)MyDataReader[0];
                    StockName = (string)MyDataReader[1];
                    UpdateStock(StockID);
                    //lock ((object) PStruct)
                    //{
                    //    PStruct.ProgressStock = "正在更新" + StockName + "(" + StockID + ")";
                    //    PStruct.ProgressSum++;
                    //}
                    
                   Invoke_CallProgress myICP = new Invoke_CallProgress(CallProgress);
                   PStruct.ProgressSum++;
                   BeginInvoke(myICP,"正在更新" + StockName + "(" + StockID + ")",PStruct.ProgressSum); 
                    UpdateAllThread.Suspend();
                    //if (StockID == "000007")
                    //    break;
                }    
    最后
    lz在“全部股票更新ToolStripMenuItem_Click”方法中的
                while (PStruct.ProgressSum <= TotalStockNum)
                {
                    AllUD.Refresh();
                    if(UpdateAllThread.ThreadState == ThreadState.Suspended||UpdateAllThread.ThreadState == ThreadState.SuspendRequested)
                    {
                        lock ((object)PStruct)
                        {                        AllUD.progressBar1.Value = PStruct.ProgressSum;
                            AllUD.label1.Text = PStruct.ProgressStock;
                        }
                        //AllUD.Refresh();
                        UpdateAllThread.Resume();
                        MyDataGridView.Refresh();
                        menuStrip1.Refresh();
                    }
                    if(UpdateAllThread.ThreadState == ThreadState.Stopped)
                        break;
                    //Thread.Sleep(10);
                } 这段代码就可以注释掉了,在主进程中开启while循环来刷新控件的显示,及时是加上了sleep也会使cpu占用率很高。<以上代码未经测试,是直接写在回复框中的,lz可参考思路,自行测试>补充建议:
    1、在UpdateProgress()方法中,若要调用窗体控件,一定要使用Invoke委托来调用。
    2、建议lz的代码分分层:数据库操作的部分用一个类、业务代码独立为一个单独的方法、界面的按钮事件仅调用独立的业务方法。否则,如果将来需求有所改动,你的工作量可大了去了。
      

  8.   

    恩,貌似就是这个问题,我试了下,就是while循环引起的,貌似while循环会占用ui的很多资源,然后就假死了,呵呵~谢谢~你代码很有用~结贴去了