一個控件需要雙擊兩次的問題

轉至:http://www.cnblogs.com/oec2003/archive/2009/12/20/1628412.html

相關問題:c#中使用多線程訪問winform中控件的若干問題

我所修改的動態顯示數據代碼: 

Thread thr = new Thread(new ThreadStart(delegate()
            {
                while (true)
                {
                    Thread.Sleep(100);
                    try
                    {
                        this.Invoke(new Action(delegate() { label1.Text = DateTime.Now.ToString(); }));
                    }
                    catch
                    {
                    }
                }
            }));
            thr.IsBackground = true;
            thr.Start();

以下代碼佔用CPU資源過高

ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object o)
                {
                    while (true)
                    {
                        this.Invoke(new Action(delegate() { label1.Text = DateTime.Now.ToString(); }));
                    }
                }));

 

資料如下:

在開發Window應用程序的時候,經常需要在界面上顯示出已經執行到什麼步驟了,拿一個簡單例子來說,創建一個Winform程序,在窗體上訪一個Button和一個Label,點擊Button時做100次循環,在Label上實時顯示當前循環的次數。一種簡單的做法就是使用Application.DoEvents,代碼如下:

private void btnTest_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 100; i++)
    {
        Thread.Sleep(100);
        label1.Text = i + "/100";
        Application.DoEvents();
    }
}

上面的代碼如果將Application.DoEvents();去掉當點擊Button時,程序會卡住,直到這個循環執行完成,當這個循環足夠大時是不能忍受的。不過小數據量用Application.DoEvents()還行,數據量大了使用Application.DoEvents()就會帶來性能的問題。所以Application.DoEvents()要慎用,在大數據量的時候可以使用多線程解決。如下:

private void btnTest_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(new ThreadStart(DoWork));
    thread.Start();
}
private void DoWork()
{
    for (int i = 0; i < 100; i++)
    {
        Thread.Sleep(100);
        label1.Text = i + "/100";
    }
}

 

嗯?出現異常了是吧,沒錯上面的代碼運行後後會出現“線程間操作無效: 從不是創建控件“label1”的線程訪問它。”的異常。關於什麼原因造成的,大家可以google一下。不過上面代碼在vs03中貌似可以正常運行。將代碼改成下面這樣就可以正常運行了:

private void btnTest_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(new ThreadStart(DoWork));
    thread.Start();
}
private void DoWork()
{
    for (int i = 0; i < 100; i++)
    {
        Thread.Sleep(100);
        this.Invoke(new Action<string>(this.ChangeLabel),i.ToString());
    }
}
private void ChangeLabel(string i)
{
    label1.Text = i + "/100";
}

 

如果嫌多寫一個ChangeLabel方法費事,可以寫成匿名方法的形式,如下:

private void btnTest_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(new ThreadStart(DoWork));
    thread.Start();
}
private void DoWork()
{
    for (int i = 0; i < 100; i++)
    {
        Thread.Sleep(100);
        this.Invoke(new Action(delegate(){label1.Text=i+"/100";}));
    }
}

同樣可以使用匿名方法的方式將DoWork方法也去掉:

private void btnTest_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(new ThreadStart(delegate() {
        for (int i = 0; i < 100; i++)
        {
            Thread.Sleep(100);
            this.Invoke(new Action(delegate() { label1.Text = i + "/100"; }));
        }
    }));
    thread.Start();
}

如果想傳參數到Dowork方法中,那麼就不能使用ThreadStart類了,應該使用ParameterizedThreadStart類,如下:

private void btnTest_Click(object sender, EventArgs e)
{
    string name = "oec2003";
    Thread thread = new Thread(new ParameterizedThreadStart(DoWork));
    thread.Start(name);
}
private void DoWork(object name)
{
    for (int i = 0; i < 100; i++)
    {
        Thread.Sleep(100);
        this.Invoke(new Action(delegate(){label1.Text=name+":"+ i+"/100";}));
    }
}

 

同樣我們也可以使用線程池的方式來實現

private void btnTest_Click(object sender, EventArgs e)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
}
private void DoWork(object o)
{
    for (int i = 0; i < 100; i++)
    {
        Thread.Sleep(100);
        this.Invoke(new Action(delegate(){label1.Text=i+"/100";}));
    }
}

 

使用匿名方法的方式:

private void btnTest_Click(object sender, EventArgs e)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object o)
    {
        for (int i = 0; i < 100; i++)
        {
            Thread.Sleep(100);
            this.Invoke(new Action(delegate() { label1.Text = i + "/100"; }));
        }
    }));
}

 

 

發佈了64 篇原創文章 · 獲贊 8 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章