亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

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

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

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

肇州县| 马山县| 普兰县| 仪征市| 克山县| 龙井市| 霍山县| 探索| 勐海县| 台前县| 泰来县| 芦山县| 上蔡县| 庄浪县| 潼南县| 夏河县| 邹城市| 喀喇沁旗| 开江县| 屯门区| 彭泽县| 平凉市| 萝北县| 仙游县| 濉溪县| 平南县| 湘阴县| 隆子县| 昆明市| 洞口县| 商城县| 崇阳县| 亳州市| 任丘市| 沙湾县| 中西区| 南溪县| 漳州市| 精河县| 渝北区| 木兰县|