台灣最大程式設計社群網站
線上人數
1114
 
會員總數:246631
討論主題:190056
歡迎您免費加入會員
討論區列表 >> C# >> 關於this.Invokerequire = true 的時機 (重發)
[]  
[我要回覆]
1
回應主題 加入我的關注話題 檢舉此篇討論 將提問者加入個人黑名單
關於this.Invokerequire = true 的時機 (重發)
價值 : 200 QP  點閱數:388 回應數:3
樓主

森森錐
門外漢
0 2
12 1
發送站內信

因上篇敘述有誤,故結案 請以此篇為主
---
小弟最近遇到一個問題,
以下是需求動作:
程式內部有一個Thread時時抓取PLC的信號,並且當訊號觸發時,將呼叫新的視窗,視窗介面提供用戶設置數值
並且經爬文後,使用this.invoke 的方式去作跨執行緒開啟UI
當視窗彈出時,會發生異常異常如下 :
在创建窗口句柄之前,は法在控件上调用Invoke或BeginInvoke
(Invoke or BeginInvoke cannot be called on a control until the window handle has been created)
實際進入Debug 發現此段的this.InvokeRequired = false
程式碼如下:


後來我使用控件觸發bool變數 來替代原本PLC的信號 卻發現可以正常開啟視窗
程式碼如下:



我的問題是:
如果使用PLC當作信號時將不會觸發this.InvokeReqiured 導致程式開啟後報錯,但當我使用控件觸發bool當作信號時this.InvokeRequired卻觸發了
有板友知道這是為什麼嗎? 有沒有什麼方法可以使用PLC信號觸發,並且讓this.InvokeRequired = true
不勝感激~

搜尋相關Tags的文章: [ this.Invoke ] , [ this.InvokeRequired ] ,
本篇文章發表於2021-04-29 11:18
1樓
回應

春天
檢舉此回應
Invoke or BeginInvoke cannot be called on a control until the window handle has been created
拋異常是因為Form還沒完全初始化就呼叫Invoke,訊息其實已經跟你說原因了
那麼什麼時候window handle才會建立? 我能確定的是在Load事件後已經建立了
所以你可以試一下以下兩個寫法,一個會出一樣的異常,一個不會




所以問題就出在你的Thread.Start之後在Form.Load之前就已經觸發事件J1RequirePalletID
而Button不會觸發,那是因為你能按Button的時候Form早已Load完畢
本篇文章回覆於2021-04-29 11:47
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
2樓
作者回應

森森錐
檢舉此回應
您好 解決了 ! (灑花
後來把輪巡的Thread放在Form_Load就可以了
測試完後發現以下兩種方法都可以,第一種如您所講,第二種則是放在InitializeComponent()下方,但當Thread執行時需要延時一秒讓控件初始化
但是這會有個問題就是兩種方法都一定要先執行此Form才會觸發Form_Load事件,如果有多個Form時只能把此Form當作主頁面,
於是開啟測試
frm_Auto Before InitializeComponent :InvokeRequire :False //InitializeComponent 前
frm_Auto After InitializeComponent :InvokeRequire :False //InitializeComponent 後
frm_Auto Create new Form InvokeRequire :False //創建New Form 時
frm_Auto after Form.show() InvokeRequire :False //Form.Show 後
frm_Auto Before Form.Load InvokeRequire :False //Form.Load 前
frm_Auto After Form.Load InvokeRequire :False //Form.Load 後
frm_Auto Before This.Invoke InvokeRequire :True //實際Invoke前

測試完後感覺白測了...找不到什麼邏輯性 Q _ Q

測試完程式碼如下:





本篇文章回覆於2021-04-29 13:33
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
3樓
最有價值解答

春天
檢舉此回應
依據MSDNInvokeRequired說明
取得一個值。這個值會指示是否由於呼叫端是在建立控制項之執行緒以外的執行緒
True = 是在建立控制項之執行緒以外的執行緒
False = "不"是在建立控制項之執行緒以外的執行緒

一般MainForm就是主執行緒(Main thread),在VisualStudio Debug時可以透過選單(偵錯) => (視窗) => (執行緒) 開啟執行緒視窗查看中斷模式(break mode)下當前執行堆疊的所屬執行緒

執行以下,可以看到因為this.Invoke的關係,執行緒被切換至建立Form1的執行緒(Main thread)


如果將Task.Run(()=> { ... });取消註解再次中斷,會發現執行緒已經被切換到背景執行緒

再將//newForm.Owner = this;取消註解,newForm會被視為Form1的子系,再呼叫Show(),此時會出現System.InvalidOperationException "跨執行緒作業無效"

這是因為在非建立某Control的執行緒,卻去操作Control的異常情形

所以你的測試基本上是沒問題的

frm_Auto Before InitializeComponent :InvokeRequire :False //InitializeComponent 前 Form1 建構式,當然是Main thread
frm_Auto After InitializeComponent :InvokeRequire :False //InitializeComponent 後 Form1 建構式,當然是Main thread
frm_Auto Create new Form InvokeRequire :False //創建New Form 時 Form1 Invoke,切換至Main thread執行
frm_Auto after Form.show() InvokeRequire :False //Form.Show 後 Form1 Invoke,切換至Main thread執行
frm_Auto Before Form.Load InvokeRequire :False //Form.Load 前 這個不確定你怎麼測試的,程式碼中看不出來
frm_Auto After Form.Load InvokeRequire :False //Form.Load 後 這個不確定你怎麼測試的,程式碼中看不出來
frm_Auto Before This.Invoke InvokeRequire :True //實際Invoke前 GiveJ1PalletIDEvent的Callback,當然不是Main thread

簡而言之,當在建立Control的Thread中調用InvokeRequire會得到False
而UI相關創建、操作都在Main thread中執行比較保險,畢竟這是Framework的初始設計
本篇文章回覆於2021-04-29 15:09
== 簽名檔 ==
--未登入的會員無法查看對方簽名檔--
   
1

回覆
如要回應,請先登入.