最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#?winform?窗體控件跨線程訪問(wèn)的實(shí)現(xiàn)

 更新時(shí)間:2023年12月14日 09:47:24   作者:Big?Clever.  
在做winform開(kāi)發(fā)時(shí),如果在子線程中去設(shè)置主線程中UI控件的屬性,會(huì)出現(xiàn)“跨線程調(diào)用異?!?本文就來(lái)介紹一下C#?winform?窗體控件跨線程訪問(wèn)的實(shí)現(xiàn),感興趣的可以了解一下

在寫計(jì)算機(jī)網(wǎng)絡(luò)課設(shè)的時(shí)候,遇到一個(gè)需求:建立的服務(wù)器需要一直監(jiān)聽(tīng)來(lái)自某個(gè)端口的連接請(qǐng)求。一開(kāi)始看到我想這不是很簡(jiǎn)單嗎,正好剛剛學(xué)習(xí)了線程有關(guān)的知識(shí),直接開(kāi)個(gè)新線程掛在后臺(tái)執(zhí)行不就行了,抱著這樣簡(jiǎn)單的想法,一堆錯(cuò)誤接踵而至。

首先出現(xiàn)的問(wèn)題就是窗體控件的跨線程訪問(wèn),會(huì)出現(xiàn)這樣的一個(gè)報(bào)錯(cuò)信息:System.InvalidOperationException:“線程間操作無(wú)效: 從不是創(chuàng)建控件“textBox1”的線程訪問(wèn)它。”

去找了找解決方案,其中最簡(jiǎn)單的是這樣的一行代碼:

Control.CheckForIllegalCrossThreadCalls = false;

這行代碼只需要加到需要進(jìn)行控制的控件那里,就會(huì)讓程序忽略線程的危險(xiǎn)操作。

這樣確實(shí)就解決了問(wèn)題,但是這是一個(gè)全局的靜態(tài)變量,如果在其他地方不小心修改了這一變量,每個(gè)控件就又會(huì)崩掉。所以,正統(tǒng)的解決方法應(yīng)該是使用委托。

什么是委托?C#的委托類似于C++的函數(shù)指針,是一個(gè)可以批量執(zhí)行函數(shù)的容器。我們知道這個(gè)問(wèn)題是發(fā)生在跨線程訪問(wèn)中,那么我們?nèi)绻尯瘮?shù)調(diào)用發(fā)生在創(chuàng)建這個(gè)控件的線程中,那么就不是跨線程訪問(wèn),也就不存在這個(gè)問(wèn)題了,因此我們使用this.invoke(delegrate)來(lái)使用委托。

來(lái)解釋這種解決方法,我們?cè)O(shè)想一個(gè)簡(jiǎn)單的情景:我們需要在一個(gè)文本框中實(shí)時(shí)的更新當(dāng)前時(shí)間,我們希望同時(shí)還可以在窗體中進(jìn)行別的操作。

第一時(shí)間想到:

private void Form1_Load(object sender, EventArgs e)
{
    while(true) 
    { 
        string time = DateTime.Now.ToString();
        textBox1.Text = time;
        Thread.Sleep(1000);
    }
}

這個(gè)顯然是錯(cuò)誤的,甚至連窗口都跳不出來(lái),更別提還可以在窗口中執(zhí)行其他操作。因?yàn)檫@個(gè)while(true)循環(huán)堵死了這個(gè)窗體的加載,根本加載不出來(lái),會(huì)一直停留在加載這個(gè)環(huán)節(jié)。

然后就應(yīng)該想到使用新開(kāi)線程來(lái)解決這個(gè)問(wèn)題了:

private void Form1_Load(object sender, EventArgs e)
{
    // Control.CheckForIllegalCrossThreadCalls = false; 
    // 如果加上上面這行代碼,就可以運(yùn)行了,但是只是忽略了線程安全性
    Thread timeShower = new Thread(ShowTime);
    timeShower.IsBackground = true;
    timeShower.Start();

}
private void ShowTime()
{
    while(true)
    {
        string time = DateTime.Now.ToString();
        textBox1.Text = time;      
    }
}

很可惜,線程的第一次使用報(bào)錯(cuò)了!跨線程訪問(wèn)了textbox控件,這不安全。

接著,我們想使用委托的相關(guān)知識(shí)來(lái)解決這個(gè)問(wèn)題:

private void Form1_Load(object sender, EventArgs e)
{
    // 這個(gè)線程傳遞的是我們使用委托的那個(gè)函數(shù)
    Thread timeShower = new Thread(Textbox1ShowTime);
    timeShower.IsBackground = true;
    timeShower.Start();

}
private delegate void TextBox1Delegrate(); // 聲明了一個(gè)無(wú)參無(wú)返回的委托
private void Textbox1ShowTime()
{
    // 實(shí)例化委托,傳遞實(shí)際需要調(diào)用的ShowTime函數(shù)
    TextBox1Delegrate newDelegrate = new TextBox1Delegrate(ShowTime);
    while (true) 
    {
        this.Invoke(newDelegrate); // 這里的this代指Form1
        Thread.Sleep(1000);
    }
}
private void ShowTime()
{
    string time = DateTime.Now.ToString();
    textBox1.Text = time;
}

好的,我們已經(jīng)基本上完成了我們?cè)O(shè)想的情景。但是,我們能否一步到位,將while循環(huán)和Thread.Sleep(1000) 放到ShowTime函數(shù)中,然后直接使用委托啟動(dòng)ShowTime,就可以直接得到實(shí)時(shí)刷新的時(shí)間呢?

如果你和我一樣聰明,估計(jì)會(huì)這么想:

private void Form1_Load(object sender, EventArgs e)
{
    Thread timeShower = new Thread(Textbox1ShowTime);
    timeShower.IsBackground = true;
    timeShower.Start();

}
private delegate void TextBox1Delegrate();
private void Textbox1ShowTime()
{
    TextBox1Delegrate newDelegrate = new TextBox1Delegrate(ShowTime);
    this.Invoke(newDelegrate);
}
private void ShowTime()
{
    while (true)
    {
        string time = DateTime.Now.ToString();
        textBox1.Text = time;
        Thread.Sleep(1000);
    }
}

好的,恭喜你,獲得了一個(gè)無(wú)響應(yīng)卡死的窗口!這是為什么呢?首先我們要知道this.Invoke(function)的原理是將這個(gè)function發(fā)送到創(chuàng)建this的這個(gè)線程,在這里也就是主線程中執(zhí)行,因此來(lái)規(guī)避跨線程問(wèn)題。但是這里,我們傳了一個(gè)永真循環(huán)進(jìn)去,其實(shí)和我們一開(kāi)始想到的那個(gè)代碼沒(méi)有本質(zhì)上的區(qū)別,能顯現(xiàn)出窗口只是因?yàn)槲覀兪褂昧宋校沁€是進(jìn)步了,恭喜我們)。

那么應(yīng)該怎么樣才能實(shí)現(xiàn)一步到位的解決這個(gè)實(shí)時(shí)顯示時(shí)間的問(wèn)題呢?

好,其實(shí)我也實(shí)現(xiàn)不了一步到位,如果有大神會(huì)的,一定要在評(píng)論區(qū)教教我QAQ

但是可以實(shí)現(xiàn)一個(gè)兩重外包,然后實(shí)現(xiàn)直接調(diào)用委托實(shí)時(shí)顯示時(shí)間。究其根本,只要不把永真的while循環(huán)放到主線程中執(zhí)行,就可以了,所以這兩重外包就是把while單獨(dú)分離了(其實(shí)上面那種實(shí)現(xiàn)方法也是同樣的思路,分離了永真while這個(gè)討厭的東西)

private void Form1_Load(object sender, EventArgs e)
{
    Thread timeShower = new Thread(Textbox1ShowTime);
    timeShower.IsBackground = true;
    timeShower.Start();

}
private delegate void TextBox1Delegrate();
private void Textbox1ShowTime()
{
    TextBox1Delegrate newDelegrate = new TextBox1Delegrate(ShowTime);
    newDelegrate.Invoke();
}
private void ShowTime()
{
    while (true)
    {
        TextBox1Delegrate newDelegrate = new TextBox1Delegrate(ShowTime1);
        this.Invoke(newDelegrate);
        Thread.Sleep(1000);
    }
}
private void ShowTime1()
{
    string time = DateTime.Now.ToString();
    textBox1.Text = time;
}

同樣的,順著分離這個(gè)思路走下去其實(shí)還可以進(jìn)一步精簡(jiǎn)我們的代碼。

這邊要提到一個(gè)屬性 textBox1.InvokeRequired。這個(gè)屬性是bool類型,他表示獲取一個(gè)值,該值指示調(diào)用方在對(duì)控件進(jìn)行方法調(diào)用時(shí)是否因?yàn)檎{(diào)用的方法于不在創(chuàng)建控件的線程中,是否必須調(diào)用 Invoke 方法。

對(duì)于有許多控件和線程需要進(jìn)行操作的情況而言,這個(gè)屬性可以非常方便的確定是否需要使用Invoke()方法進(jìn)行委托的調(diào)用

對(duì)于我們這個(gè)從子線程Textbox1ShowTime()進(jìn)去的ShowTime而言,這個(gè)屬性永遠(yuǎn)是真的;而對(duì)于我們使用this.Invoke(newDelegrate)使用的ShowTime而言,它相當(dāng)于是在主線程中執(zhí)行這個(gè)函數(shù),從而實(shí)現(xiàn)了狀態(tài)的分離。因此我們可以通過(guò)if(textBox1.InvokeRequired)實(shí)現(xiàn)將ShowTime1放到ShowTime中實(shí)現(xiàn)

private void Form1_Load(object sender, EventArgs e)
{
    Thread timeShower = new Thread(Textbox1ShowTime);
    timeShower.IsBackground = true;
    timeShower.Start();

}
private delegate void TextBox1Delegrate();
private void Textbox1ShowTime()
{
    TextBox1Delegrate newDelegrate = new TextBox1Delegrate(ShowTime);
    newDelegrate.Invoke();
}
private void ShowTime()
{
    if (textBox1.InvokeRequired) // 從new Thread(Textbox1ShowTime)調(diào)用的委托一定會(huì)進(jìn)這里
    {
        while (true)
        {
            TextBox1Delegrate newDelegrate = new TextBox1Delegrate(ShowTime);
            this.Invoke(newDelegrate); // 這個(gè)相當(dāng)于是在主線程調(diào)用委托
            Thread.Sleep(1000); // 注意這個(gè)sleep不能放到else中,不然會(huì)無(wú)限的休眠
        }
    }
    else // 從主線程調(diào)用的委托一定會(huì)進(jìn)到這里
    {
        string time = DateTime.Now.ToString();
        textBox1.Text = time;
    }

}

OK,針對(duì)這個(gè)跨線程訪問(wèn)的例子暫時(shí)我只能想這么多了,有錯(cuò)誤的話大佬們不靈賜教啊QAQ

到此這篇關(guān)于C# winform 窗體控件跨線程訪問(wèn)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C# winform跨線程訪問(wèn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#判斷字符串是否是int/double(實(shí)例)

    C#判斷字符串是否是int/double(實(shí)例)

    本文主要分享了C#判斷字符串是否是int/double的具體實(shí)例,具有一定的參考價(jià)值,需要的朋友一起來(lái)看下吧
    2016-12-12
  • C#實(shí)現(xiàn)十五子游戲

    C#實(shí)現(xiàn)十五子游戲

    這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)十五子游戲的相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • C#中TaskFactory實(shí)現(xiàn)線程任務(wù)

    C#中TaskFactory實(shí)現(xiàn)線程任務(wù)

    TaskFactory是C#中處理多線程和異步任務(wù)的一個(gè)非常有用的類,它通過(guò)簡(jiǎn)化任務(wù)的創(chuàng)建、啟動(dòng)、調(diào)度和管理,極大提高了開(kāi)發(fā)效率和代碼可讀性,下面就詳細(xì)的介紹一下如何使用,感興趣的可以了解一下
    2025-12-12
  • WPF自定義實(shí)現(xiàn)雷達(dá)圖控件的示例詳解

    WPF自定義實(shí)現(xiàn)雷達(dá)圖控件的示例詳解

    雷達(dá)圖用于表示不同內(nèi)容的占比關(guān)系,在項(xiàng)目中有廣泛的應(yīng)用,但是目前未曾有封裝良好的雷達(dá)圖控件,所以本文分享了如何封裝一個(gè)通用的雷達(dá)圖控件,希望對(duì)大家有所幫助
    2023-08-08
  • C#中WebBrowser.DocumentCompleted事件多次調(diào)用問(wèn)題解決方法

    C#中WebBrowser.DocumentCompleted事件多次調(diào)用問(wèn)題解決方法

    這篇文章主要介紹了C#中WebBrowser.DocumentCompleted事件多次調(diào)用問(wèn)題解決方法,本文講解了3種情況和各自情況的解決方法,需要的朋友可以參考下
    2015-01-01
  • Unity實(shí)現(xiàn)角色受擊身體邊緣發(fā)光特效

    Unity實(shí)現(xiàn)角色受擊身體邊緣發(fā)光特效

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)角色受擊身體邊緣發(fā)光特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • C#調(diào)用OpenXml操作word文檔的基本用法介紹

    C#調(diào)用OpenXml操作word文檔的基本用法介紹

    本文詳細(xì)介紹了使用圖形類Drawing將圖表和數(shù)據(jù)保存到Word文檔的方法,強(qiáng)調(diào)了GraphicData類型的關(guān)鍵作用并展示了具體代碼實(shí)現(xiàn)和運(yùn)行效果,有需要的小伙伴可以了解下
    2026-05-05
  • C# FileStream簡(jiǎn)單介紹和使用

    C# FileStream簡(jiǎn)單介紹和使用

    這篇文章主要為大家詳細(xì)介紹了C# FileStream基本功能和使用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • C#之日期格式轉(zhuǎn)換過(guò)程

    C#之日期格式轉(zhuǎn)換過(guò)程

    本文詳細(xì)介紹了DateTime轉(zhuǎn)字符串(ToString)及字符串轉(zhuǎn)DateTime(Parse/ParseExact/TryryuserParse/Try Pornhub在2本文詳細(xì)介紹了如何使用DateTime的ToString和Parse/ParseExact/Try總結(jié)了DateTime轉(zhuǎn)換方法,幫助開(kāi)發(fā)者更高效地處理日期時(shí)間數(shù)據(jù)
    2026-05-05
  • C#原型模式之如何通過(guò)克隆對(duì)象來(lái)優(yōu)化創(chuàng)建過(guò)程

    C#原型模式之如何通過(guò)克隆對(duì)象來(lái)優(yōu)化創(chuàng)建過(guò)程

    原型模式是一種創(chuàng)建型設(shè)計(jì)模式,通過(guò)克隆現(xiàn)有對(duì)象來(lái)創(chuàng)建新對(duì)象,避免重復(fù)的創(chuàng)建成本和復(fù)雜的初始化過(guò)程,它適用于對(duì)象創(chuàng)建過(guò)程復(fù)雜、需要大量相似對(duì)象或避免重復(fù)初始化的場(chǎng)景,本文介紹C#原型模式之如何通過(guò)克隆對(duì)象來(lái)優(yōu)化創(chuàng)建過(guò)程,感興趣的朋友一起看看吧
    2025-03-03

最新評(píng)論

五峰| 峡江县| 侯马市| 景宁| 敦煌市| 遂宁市| 孟连| 梨树县| 云霄县| 武邑县| 旺苍县| 河源市| 泽库县| 湖州市| 特克斯县| 牙克石市| 云霄县| 林周县| 武乡县| 翼城县| 甘孜县| 六安市| 桓台县| 平遥县| 同江市| 穆棱市| 砚山县| 上栗县| 屏东县| 同心县| 龙游县| 隆昌县| 浦县| 刚察县| 瑞昌市| 长海县| 曲水县| 偏关县| 锡林浩特市| 辽源市| 那坡县|