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

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

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

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

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

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

Control.CheckForIllegalCrossThreadCalls = false;

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

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

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

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

第一時間想到:

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

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

然后就應(yīng)該想到使用新開線程來解決這個問題了:

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;      
    }
}

很可惜,線程的第一次使用報錯了!跨線程訪問了textbox控件,這不安全。

接著,我們想使用委托的相關(guān)知識來解決這個問題:

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

}
private delegate void TextBox1Delegrate(); // 聲明了一個無參無返回的委托
private void Textbox1ShowTime()
{
    // 實例化委托,傳遞實際需要調(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)基本上完成了我們設(shè)想的情景。但是,我們能否一步到位,將while循環(huán)和Thread.Sleep(1000) 放到ShowTime函數(shù)中,然后直接使用委托啟動ShowTime,就可以直接得到實時刷新的時間呢?

如果你和我一樣聰明,估計會這么想:

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);
    }
}

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

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

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

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

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;
}

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

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

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

對于我們這個從子線程Textbox1ShowTime()進(jìn)去的ShowTime而言,這個屬性永遠(yuǎn)是真的;而對于我們使用this.Invoke(newDelegrate)使用的ShowTime而言,它相當(dāng)于是在主線程中執(zhí)行這個函數(shù),從而實現(xiàn)了狀態(tài)的分離。因此我們可以通過if(textBox1.InvokeRequired)實現(xiàn)將ShowTime1放到ShowTime中實現(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)用的委托一定會進(jìn)這里
    {
        while (true)
        {
            TextBox1Delegrate newDelegrate = new TextBox1Delegrate(ShowTime);
            this.Invoke(newDelegrate); // 這個相當(dāng)于是在主線程調(diào)用委托
            Thread.Sleep(1000); // 注意這個sleep不能放到else中,不然會無限的休眠
        }
    }
    else // 從主線程調(diào)用的委托一定會進(jìn)到這里
    {
        string time = DateTime.Now.ToString();
        textBox1.Text = time;
    }

}

OK,針對這個跨線程訪問的例子暫時我只能想這么多了,有錯誤的話大佬們不靈賜教啊QAQ

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

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

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

    這篇文章主要為大家詳細(xì)介紹了Unity實現(xiàn)角色受擊身體邊緣發(fā)光特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    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)鍵作用并展示了具體代碼實現(xiàn)和運(yùn)行效果,有需要的小伙伴可以了解下
    2026-05-05
  • C# FileStream簡單介紹和使用

    C# FileStream簡單介紹和使用

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

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

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

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

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

最新評論

县级市| 来凤县| 上林县| 左权县| 南昌市| 张家口市| 武威市| 烟台市| 白银市| 衡南县| 德江县| 高平市| 泉州市| 阿拉善盟| 桐柏县| 新乐市| 青川县| 万荣县| 平山县| 凤冈县| 雅江县| 志丹县| 信阳市| 淳化县| 余庆县| 邵武市| 邓州市| 无为县| 肃宁县| 禹城市| 鹤庆县| 徐水县| 盖州市| 福贡县| 嫩江县| 营口市| 清水河县| 临泉县| 莱州市| 张北县| 岑溪市|