91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C# 一個簡單的秒表引發的窗體卡死問題

發布時間:2020-06-25 16:58:06 來源:網絡 閱讀:2922 作者:我不會抽煙 欄目:編程語言

一個秒表程序也是我的一個心病,因為一直想寫這樣的一個東西,但是總往GUI那邊想,所以就比較怵,可能是上學的時候學MFC搞出的后遺癥吧,不過當我今天想好用Win Form(話說還是第一次寫win form)寫這么一個東西的時候,居然so easy。

所以說,做不了不可怕,怕的是你不去做,因為你不去做,你就永遠不知道你能不能做它。事實證明,大部分你猶豫能不能做的事情,實際上你都能搞定。

雖然成功實現了一個秒表的簡單功能,即開始計時和停止。但是卻引發了一個關于win form和C#線程的問題。

下面一個一個來,先說一下秒表的類實現

namespace Utils
{
    public class Time
    {
        private int _minute;
        private int _second;
        private bool _flag;//線程標識
        private Thread _TimingThread = null;

        public Time()
        {
            this._minute = 0;
            this._second = 0;
            this._flag = true;
        }
        /// <summary>
        /// 開始計時
        /// </summary>
        public void Start()
        {
            if (_TimingThread == null || !this._flag)
            {
                this._flag = true;
                _TimingThread = new Thread(new ThreadStart(AddSecond));
                _TimingThread.Start();
            }
        }
        /// <summary>
        /// 線程執行方法
        /// </summary>
        private void AddSecond()
        {
            while(_flag)
            {
                Thread.Sleep(1000);
                if (this._second == 59)
                {
                    this._minute++;
                    this._second = 0;
                }
                else
                {
                    this._second++;
                }
            }
        }
        /// <summary>
        /// 格式化顯示計時結果
        /// </summary>
        /// <returns></returns>
        public string FormatTimeResult()
        {
            string minute = string.Empty;
            string second = string.Empty;
            if (this._minute < 10)
            {
                minute = "0" + this._minute.ToString();
            }
            else 
            {
                minute = this._minute.ToString();
            }
            if (this._second < 10)
            {
                second = "0" + this._second.ToString();
            }
            else
            {
                second = this._second.ToString();
            }
            return minute + ":" + second;
        }
        /// <summary>
        /// 停止
        /// </summary>
        public void Stop()
        {
            this._flag = false;
        }
        /// <summary>
        /// 歸0操作
        /// </summary>
        public void Zero()
        {
            this._minute = 0;
            this._second = 0;
        }
    }
}

秒表的實現還是比較簡單的,感覺這樣寫,也方便以后做擴展。

下面說說win form方面

窗體就是這樣,一個label,兩個button

C# 一個簡單的秒表引發的窗體卡死問題

最開始,我寫了這樣一段代碼

    public partial class Form1 : Form
    {
        private Time mTime = null;
        private Thread mDisplayThread = null;

        public Form1()
        {
            InitializeComponent();
            mTime = new Time();//實例化秒表類
        }

        private void button_start_Click(object sender, EventArgs e)
        {
            mTime.Start();
            mDisplayThread = new Thread(new ThreadStart(DisplayCurrentTime));
            mDisplayThread.Start();
            button_start.Enabled = false;

        }

        public void DisplayCurrentTime()
        {
            while (true)
            {
                Thread.Sleep(1000);
                label_Time.Text = mTime.FormatTimeResult();
                Console.WriteLine("{0}", mTime.FormatTimeResult());
            }
        }
        
        private void button_stop_Click(object sender, EventArgs e)
        {
            mTime.Stop();
            button_start.Enabled = true;
        }
    }

這樣寫感覺思路上沒什么問題,當點擊【開始計時】按鈕的同時創建一個線程,而這個線程是用來每隔一秒去更新一下label上的顯示計時時間。

然而,之后卻報一個這樣的錯誤:Cross-thread operation not valid: Control 'label_Time' accessed from a thread other than the thread it was created on.

網上查了一下,這個錯誤貌似很常見,MSDN上也給了一個出現此錯誤的原因,是這樣說的,當您試圖從單獨的線程更新一個win form時,會出現這個錯誤。

查了一下,就是說win form上的控件屬性想要進行修改的時候,只能在創建Control的線程里調用,不能在以外的線程被調用。而上面的

label_Time.Text = mTime.FormatTimeResult();

這段代碼呢恰恰是發生在新創建的線程之中,所以就會報錯了。

解決辦法是用delegate(委托)加上control.Invoke去聯合實現。下面看看實現部分

public partial class Form1 : Form
    {
        private Time mTime = null;
        private Thread mDisplayThread = null;
        public delegate void UpdateLabel();//聲明一個委托
        public UpdateLabel updateLabel;//定義一個委托

        public Form1()
        {
            InitializeComponent();
            mTime = new Time();
            updateLabel = new UpdateLabel(UpdateTime);
        }

        private void button_start_Click(object sender, EventArgs e)
        {
            mTime.Start();
            mDisplayThread = new Thread(new ThreadStart(DisplayTimeFunc));
            mDisplayThread.Start();
            button_start.Enabled = false;

        }
        /// <summary>
        /// 線程執行方法
        /// </summary>
        public void DisplayTimeFunc()
        {
            while (true)
            {
                Thread.Sleep(1000);
                this.Invoke(this.updateLabel);
            }
        }

        /// <summary>
        /// 單獨對Label進行刷新
        /// </summary>
        public void UpdateTime()
        {
            label_Time.Text = mTime.FormatTimeResult();
        }

        private void button_stop_Click(object sender, EventArgs e)
        {
            mTime.Stop();
            button_start.Enabled = true;
        }

    }

這段代碼里mDisplayThread線程執行了DisplayTimeFunc方法,而DisplayTimeFunc方法里實際就是在更新label,不同的是使用了Control.Invoke方法,上面不是說對控件屬性的更改要在創建控件的線程里才執行嗎?現在看起來好像還是老樣子。那是因為我們不了解Control.Invoke是什么東東。MSDN上的解釋是:在擁有此控件的基礎窗口句柄的線程上執行指定的委托。OK,明白了,this.updateLabel這個委托最后還是在窗口創建的線程中執行的。

回頭想想,其實思路也比較簡單,就是先將更改控件屬性的操作放在一個方法里,然后寫個委托,再寫個線程,在線程的執行方法中調用這個委托就OK啦。

不過到這還不算全完,還有一個小問題,就是當我計時之后,想要關閉這個窗體的時候,發現又開始報錯了:

Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

研究了一下發現了出現此問題的原因,就是我們“上完廁所沒有擦PP”,上面的代碼中沒有一個操作是對 mDisplayThread 這個線程做了終止的動作。

所以我們還需要添加以下動作

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            mDisplayThread.Abort();
        }

這樣就完整了,在關閉Form1窗體之前,先把線程終止。

做這個小東西的時候居然連帶著讓我了解了一些委托和Control.Invoke以及線程的知識點。我會找個時間好好把這部分看看的,爭取能總結點什么出來。


新浪微博:http://weibo.com/zhouhongyu1989 歡迎圍觀~!


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

卢氏县| 五华县| 安新县| 永清县| 武平县| 连江县| 临猗县| 广南县| 娄底市| 望江县| 新源县| 龙岩市| 嘉鱼县| 儋州市| 贡觉县| 渭南市| 山丹县| 涞水县| 安图县| 浪卡子县| 饶平县| 周至县| 江油市| 横山县| 鹤庆县| 邵阳市| 来安县| 明星| 清原| 化隆| 鹤山市| 海城市| 原平市| 南雄市| 正定县| 蓝田县| 绥滨县| 毕节市| 平谷区| 横峰县| 镇雄县|