轉帖|其它|編輯:郝浩|2011-09-16 14:05:45.000|閱讀 775 次
概述:我們在做winform應用的時候,大部分情況下都會碰到使用多線程控制界面上控件信息的問題。然而我們并不能用傳統方法來解決這個問題,下面我將詳細的介紹。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
我們在做winform應用的時候,大部分情況下都會碰到使用多線程控制界面上控件信息的問題。然而我們并不能用傳統方法來解決這個問題,下面我將詳細的介紹。
首先來看傳統方法:
? ? ? ? p?u?b?l?i?c p?a?r?t?i?a?l c?l?a?s?s ?F?o?r?m?1? ?:? ?F?o?r?m?
{?
p?u?b?l?i?c ?F?o?r?m?1?(?)?
{?
I?n?i?t?i?a?l?i?z?e?C?o?m?p?o?n?e?n?t?(?)?;?
}?
p?r?i?v?a?t?e v?o?i?d ?F?o?r?m?1?_?L?o?a?d?(o?b?j?e?c?t ?s?e?n?d?e?r?,? ?E?v?e?n?t?A?r?g?s? ?e?)?
{?
T?h?r?e?a?d? ?t?h?r?e?a?d? = n?e?w ?T?h?r?e?a?d?(?T?h?r?e?a?d?F?u?n?t?i?o?n?)?;?
t?h?r?e?a?d?.?I?s?B?a?c?k?g?r?o?u?n?d? = t?r?u?e;?
t?h?r?e?a?d?.?S?t?a?r?t?(?)?;?
}?
p?r?i?v?a?t?e v?o?i?d ?T?h?r?e?a?d?F?u?n?t?i?o?n?(?)?
{?
w?h?i?l?e ?(t?r?u?e)?
{?
t?h?i?s.?t?e?x?t?B?o?x?1?.?T?e?x?t? = ?D?a?t?e?T?i?m?e?.?N?o?w?.?T?o?S?t?r?i?n?g?(?)?;?
T?h?r?e?a?d?.?S?l?e?e?p?(1?0?0?0)?;?
}?
}?
}?
運行這段代碼,我們會看到系統拋出一個異常:
Cross-thread operation not valid:Control 'textBox1' accessed from
a thread other than the thread it was created on .
這是因為.net 2.0以后加強了安全機制,不允許在winform中直接跨線程訪問控件的屬性。那么怎么解決這個問題呢,下面提供幾種方案。
第一種方案,我們在Form1_Load()方法中加一句代碼:
? ? ? ? ? p?r?i?v?a?t?e v?o?i?d ?F?o?r?m?1?_?L?o?a?d?(o?b?j?e?c?t ?s?e?n?d?e?r?,? ?E?v?e?n?t?A?r?g?s? ?e?)?
{?
C?o?n?t?r?o?l?.?C?h?e?c?k?F?o?r?I?l?l?e?g?a?l?C?r?o?s?s?T?h?r?e?a?d?C?a?l?l?s? = f?a?l?s?e;?
T?h?r?e?a?d? ?t?h?r?e?a?d? = n?e?w ?T?h?r?e?a?d?(?T?h?r?e?a?d?F?u?n?t?i?o?n?)?;?
t?h?r?e?a?d?.?I?s?B?a?c?k?g?r?o?u?n?d? = t?r?u?e;?
t?h?r?e?a?d?.?S?t?a?r?t?(?)?;?
}
加入這句代碼以后發現程序可以正常運行了。這句代碼就是說在這個類中我們不檢查跨線程的調用是否合法(如果沒有
加這句話運行也沒有異常,那么說明系統以及默認的采用了不檢查的方式)。然而,這種方法不可取。我們查看 CheckForIllegalCrossThreadCalls 這個屬性的定義,就會發現它是一個static的,也就是說無論我們在項目的什么地方修改了這個值,他就會在全局起作用。而且像這種跨線程訪問是否存在異常,我們通常都會去檢查。如果項目中其他人修改了這個屬性,那么我們的方案就失敗了,我們要采取另外的方案。
下面來看第二種方案,就是使用delegate和invoke來從其他線程中控制控件信息。網上有很多人寫了這種控制方式,然而我看了很多這種帖子,表明上看來是沒有什么問題的,但是實際上并沒有解決這個問題,首先來看網絡上的那種不完善的方式:
? ? ? p?u?b?l?i?c p?a?r?t?i?a?l c?l?a?s?s ?F?o?r?m?1? ?:? ?F?o?r?m?
{?
p?r?i?v?a?t?e d?e?l?e?g?a?t?e v?o?i?d ?F?l?u?s?h?C?l?i?e?n?t?(?)?;/?/代?理
p?u?b?l?i?c ?F?o?r?m?1?(?)?
{?
I?n?i?t?i?a?l?i?z?e?C?o?m?p?o?n?e?n?t?(?)?;?
}?
p?r?i?v?a?t?e v?o?i?d ?F?o?r?m?1?_?L?o?a?d?(o?b?j?e?c?t ?s?e?n?d?e?r?,? ?E?v?e?n?t?A?r?g?s? ?e?)?
{?
T?h?r?e?a?d? ?t?h?r?e?a?d? = n?e?w ?T?h?r?e?a?d?(?C?r?o?s?s?T?h?r?e?a?d?F?l?u?s?h?)?;?
? ? ? ? ? ? ? ? ? ? ? ?t?h?r?e?a?d?.?I?s?B?a?c?k?g?r?o?u?n?d=t?r?u?e;?
t?h?r?e?a?d?.?S?t?a?r?t?(?)?;?
}?
? ? ? ? ? ? ? p?r?i?v?a?t?e v?o?i?d ?C?r?o?s?s?T?h?r?e?a?d?F?l?u?s?h?(?)?
{?
/?/將?代?理?綁?定?到?方?法?
F?l?u?s?h?C?l?i?e?n?t? ?f?c? = n?e?w ?F?l?u?s?h?C?l?i?e?n?t?(?T?h?r?e?a?d?F?u?n?t?i?o?n?)?;?
t?h?i?s.?B?e?g?i?n?I?n?v?o?k?e?(?f?c?)?;/?/調?用?代?理
}?
p?r?i?v?a?t?e v?o?i?d ?T?h?r?e?a?d?F?u?n?t?i?o?n?(?)?
{?
w?h?i?l?e ?(t?r?u?e)?
{?
t?h?i?s.?t?e?x?t?B?o?x?1?.?T?e?x?t? = ?D?a?t?e?T?i?m?e?.?N?o?w?.?T?o?S?t?r?i?n?g?(?)?;?
T?h?r?e?a?d?.?S?l?e?e?p?(1?0?0?0)?;?
}?
}?
}?
使用這種方式我們可以看到跨線程訪問的異常沒有了。但是新問題出現了,界面沒有響應了。為什么會出現這個問題,
我們只是讓新開的線程無限循環刷新,理論上應該不會對主線程產生影響的。其實不然,這種方式其實相當于把這個新開的線程“注入”到了主控制線程中,它取得了主線程的控制。只要這個線程不返回,那么主線程將永遠都無法響應。就算新開的線程中不使用無限循環,使可以返回了。這種方式的使用多線程也失去了它本來的意義。
現在來讓我們看看推薦的解決方案:
? ? ? p?u?b?l?i?c p?a?r?t?i?a?l c?l?a?s?s ?F?o?r?m?1? ?:? ?F?o?r?m?
{?
p?r?i?v?a?t?e d?e?l?e?g?a?t?e v?o?i?d ?F?l?u?s?h?C?l?i?e?n?t?(?)?;/?/代?理
p?u?b?l?i?c ?F?o?r?m?1?(?)?
{?
I?n?i?t?i?a?l?i?z?e?C?o?m?p?o?n?e?n?t?(?)?;?
}?
p?r?i?v?a?t?e v?o?i?d ?F?o?r?m?1?_?L?o?a?d?(o?b?j?e?c?t ?s?e?n?d?e?r?,? ?E?v?e?n?t?A?r?g?s? ?e?)?
{?
T?h?r?e?a?d? ?t?h?r?e?a?d? = n?e?w ?T?h?r?e?a?d?(?C?r?o?s?s?T?h?r?e?a?d?F?l?u?s?h?)?;?
t?h?r?e?a?d?.?I?s?B?a?c?k?g?r?o?u?n?d? = t?r?u?e;?
t?h?r?e?a?d?.?S?t?a?r?t?(?)?;?
}?
? ? ? ? ? ? ? p?r?i?v?a?t?e v?o?i?d ?C?r?o?s?s?T?h?r?e?a?d?F?l?u?s?h?(?)?
{?
w?h?i?l?e ?(t?r?u?e)?
{?
/?/將?s?l?e?e?p?和?無?限?循?環?放?在?等?待?異?步?的?外?面
T?h?r?e?a?d?.?S?l?e?e?p?(1?0?0?0)?;?
T?h?r?e?a?d?F?u?n?c?t?i?o?n?(?)?;?
}?
}?
p?r?i?v?a?t?e v?o?i?d ?T?h?r?e?a?d?F?u?n?c?t?i?o?n?(?)?
{?
i?f ?(t?h?i?s.?t?e?x?t?B?o?x?1?.?I?n?v?o?k?e?R?e?q?u?i?r?e?d?)/?/等?待?異?步
{?
F?l?u?s?h?C?l?i?e?n?t? ?f?c? = n?e?w ?F?l?u?s?h?C?l?i?e?n?t?(?T?h?r?e?a?d?F?u?n?c?t?i?o?n?)?;?
t?h?i?s.?I?n?v?o?k?e?(?f?c?)?;/?/通?過?代?理?調?用?刷?新?方?法
}?
e?l?s?e
{?
t?h?i?s.?t?e?x?t?B?o?x?1?.?T?e?x?t? = ?D?a?t?e?T?i?m?e?.?N?o?w?.?T?o?S?t?r?i?n?g?(?)?;?
}?
}?
}?
運行上述代碼,我們可以看到問題已經被解決了,通過等待異步,我們就不會總是持有主線程的控制,這樣就可以在
不發生跨線程調用異常的情況下完成多線程對winform多線程控件的控制了。
對于深山老林提出的問題,我最近找到了更優的解決方案,利用了delegate的異步調用,大家可以看看:
? ? ? p?u?b?l?i?c p?a?r?t?i?a?l c?l?a?s?s ?F?o?r?m?1? ?:? ?F?o?r?m?
{?
p?r?i?v?a?t?e d?e?l?e?g?a?t?e v?o?i?d ?F?l?u?s?h?C?l?i?e?n?t?(?)?;/?/代?理
p?u?b?l?i?c ?F?o?r?m?1?(?)?
{?
I?n?i?t?i?a?l?i?z?e?C?o?m?p?o?n?e?n?t?(?)?;?
}?
p?r?i?v?a?t?e v?o?i?d ?F?o?r?m?1?_?L?o?a?d?(o?b?j?e?c?t ?s?e?n?d?e?r?,? ?E?v?e?n?t?A?r?g?s? ?e?)?
{?
T?h?r?e?a?d? ?t?h?r?e?a?d? = n?e?w ?T?h?r?e?a?d?(?C?r?o?s?s?T?h?r?e?a?d?F?l?u?s?h?)?;?
t?h?r?e?a?d?.?I?s?B?a?c?k?g?r?o?u?n?d? = t?r?u?e;?
t?h?r?e?a?d?.?S?t?a?r?t?(?)?;?
}?
? ? ? ? ? ? ? p?r?i?v?a?t?e v?o?i?d ?C?r?o?s?s?T?h?r?e?a?d?F?l?u?s?h?(?)?
{?
? ? ? ? ? ? ? ? ? ? ? ? ?F?l?u?s?h?C?l?i?e?n?t? ?f?c=n?e?w ?F?l?u?s?h?C?l?i?e?n?t?(?T?h?r?e?a?d?F?u?n?c?t?i?o?n?)?;?
? ? ? ? ? ? ? ? ? ? ? ? ?f?c?.?B?e?g?i?n?I?n?v?o?k?e?(n?u?l?l,n?u?l?l)?;?
}?
p?r?i?v?a?t?e v?o?i?d ?T?h?r?e?a?d?F?u?n?c?t?i?o?n?(?)?
{?
? ? ? ? ? ? ? ? ? ? ? ? ? w?h?i?l?e ?(t?r?u?e)?
{?
t?h?i?s.?t?e?x?t?B?o?x?1?.?T?e?x?t? = ?D?a?t?e?T?i?m?e?.?N?o?w?.?T?o?S?t?r?i?n?g?(?)?;?
T?h?r?e?a?d?.?S?l?e?e?p?(1?0?0?0)?;?
}?
? ? ? ? ? ? ? ?}?
}?
這種方法也可以直接簡化為(因為delegate的異步就是開了一個異步線程):
? ? ? p?u?b?l?i?c p?a?r?t?i?a?l c?l?a?s?s ?F?o?r?m?1? ?:? ?F?o?r?m?
{?
p?r?i?v?a?t?e d?e?l?e?g?a?t?e v?o?i?d ?F?l?u?s?h?C?l?i?e?n?t?(?)?;/?/代?理
p?u?b?l?i?c ?F?o?r?m?1?(?)?
{?
I?n?i?t?i?a?l?i?z?e?C?o?m?p?o?n?e?n?t?(?)?;?
}?
p?r?i?v?a?t?e v?o?i?d ?F?o?r?m?1?_?L?o?a?d?(o?b?j?e?c?t ?s?e?n?d?e?r?,? ?E?v?e?n?t?A?r?g?s? ?e?)?
{?
F?l?u?s?h?C?l?i?e?n?t? ?f?c=n?e?w ?F?l?u?s?h?C?l?i?e?n?t?(?T?h?r?e?a?d?F?u?n?c?t?i?o?n?)?;? ?
? ? ? ? ? ? ? ? ? ? ? ? ?f?c?.?B?e?g?i?n?I?n?v?o?k?e?(n?u?l?l,n?u?l?l)?;?
}?
? ? ? ? ? ? ? ? p?r?i?v?a?t?e v?o?i?d ?T?h?r?e?a?d?F?u?n?c?t?i?o?n?(?)?
{?
? ? ? ? ? ? ? ? ? ? ? ? ? w?h?i?l?e ?(t?r?u?e)?
{?
t?h?i?s.?t?e?x?t?B?o?x?1?.?T?e?x?t? = ?D?a?t?e?T?i?m?e?.?N?o?w?.?T?o?S?t?r?i?n?g?(?)?;?
T?h?r?e?a?d?.?S?l?e?e?p?(1?0?0?0)?;?
}?
? ? ? ? ? ? ? ?}?
}?
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:網絡轉載