none
Invoke與多執行緒問題 RRS feed

  • 問題

  • 各位大大,我有一個問題想請教,Invoke呼叫有沒有辦法支援在下面這種情況下執行.

    我希望能顯示一個視窗,利用那個視窗來秀下載資料花了多少時間,可是根據我的測試,Invoke呼叫會在按下按鈕後等while迴圈都跑完了才會去更新畫面上的東西,有沒有辦法在while迴圈跑的同時也更新畫面上顯示的時間??因為主要的程式是一個透過Remoting抓取大量資料的函數呼叫,所以會在那一行hold住一陣子,請問有沒有在不影響現行程式架構的情況下,能讓畫面更新的方法??

    在VS2003環境下我可以直接在執行緒中對控制項作操作,但是在VS2005則無法正常操作,請教高手其中是否有什麼差異?VS2005能否降低安全性讓這方法可正常運作?

    拜託各位高手了><

    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 TestInvoke
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }

            private DateTime t1;
            private Thread thread1;

            public delegate void ChangeLabelDelegate(Label l);

            private void ChangeLabel(Label l)
            {
                DateTime t2 = DateTime.Now;
                int sec = ((TimeSpan)(t2 - t1)).Seconds;
                l.Text = sec.ToString() + " sec";
                this.Refresh();
            }

            private void button1_Click(object sender, EventArgs e)
            {
                t1 = DateTime.Now;
                thread1 = new Thread(new ThreadStart(RunThread));
                //RunThread();
                thread1.Start();
                long i = 0;
                while (i < int.MaxValue)
                {
                    i++;
                }
                MessageBox.Show("End Button");
            }

            private void RunThread()
            {
                int i = 0;
                while (i < 3000)
                {
                    this.label1.Invoke(new ChangeLabelDelegate(ChangeLabel), this.label1);
                    //this.label1.Text = i.ToString();
                    Application.DoEvents();
                    //Console.WriteLine(i.ToString());
                    Thread.Sleep(10);
                    i++;
                }
            }
        }
    }

    2007年2月9日 上午 07:27

解答

所有回覆

  • 就您貼的這段程式碼,只要在迴圈裏面加上 Application.DoEvents();
    前 10 秒 lebel 的文字就不會定格..

    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 TestInvoke
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }

            private DateTime t1;
            private Thread thread1;

            public delegate void ChangeLabelDelegate(Label l);

            private void ChangeLabel(Label l)
            {
                DateTime t2 = DateTime.Now;
                int sec = ((TimeSpan)(t2 - t1)).Seconds;
                l.Text = sec.ToString() + " sec";
                this.Refresh();
            }

            private void button1_Click(object sender, EventArgs e)
            {
                t1 = DateTime.Now;
                thread1 = new Thread(new ThreadStart(RunThread));
                thread1.Start();
                long i = 0;
                while (i < int.MaxValue)
                {
                    i++;
                    // 加上 DoEvents
                    Application.DoEvents();
                }
                MessageBox.Show("End Button");
            }

            private void RunThread()
            {
                int i = 0;
                while (i < 3000)
                {
                    this.label1.Invoke(new ChangeLabelDelegate(ChangeLabel), this.label1);
                    Application.DoEvents();
                    Thread.Sleep(10);
                    i++;
                }
            }
        }
    }

    2007年2月9日 上午 08:36
  • 這方式我亦有嘗試過,但實際上的程式沒有辦法貼上一個Application.Doevents()

    因為實際上的程式是一段呼叫Remoting以取得資料

                t1 = DateTime.Now;
                thread1 = new Thread(new ThreadStart(RunThread));
                thread1.Start();
                long i = 0;
                //while (i < int.MaxValue)
                //{
                 //   i++;
                   
    // 加上 DoEvents
                //    Application.DoEvents();

                //}

                DataTable dt = XXX.GetRemotingData(); // 單純的呼叫遠端Remoting 取得DataTable
                MessageBox.Show("End Button");

    因為資料量過於龐大,導致讀取的時間太久,而我自行測試的時候,沒有實際去抓取資料,所以改用一個迴圈來模擬該情況.

    該Remoting使用SingleCall方式呼叫,因此沒辦法在中間加入Application.DoEvents();

    2007年2月9日 上午 08:43
  • 如果不嫌棄看 VB2005 ,這邊有觀念及小範例:

    http://tlcheng.spaces.live.com/blog/cns!145419920BFD55A7!1440.entry

    裡面另有個連結指到本站討論的範例修改:

    http://forums.microsoft.com/MSDN-CHT/ShowPost.aspx?PostID=1024049&SiteID=14

    2007年2月9日 上午 09:34