[英]Why doesn't my Textbox update with Thread-safe calls using InvokeRequired?
[英]Why doesn't my event handler update my Windows Form textbox?
誰能解釋或顯示為什么我的事件處理程序不更新Windows窗體文本框? 我將事件處理程序放在UI線程中,以更新GUI窗口中的文本框。 我的UI線程#1 SetOperation類中的EventLaunch方法啟動一個事件。 UI線程#1 SetOperation類OnChDetDisplay事件處理程序完成,但“窗口窗體”文本框未更新為分配的值。 將事件和處理程序與更新文本框聯系在一起時,我缺少什么?
感謝任何人都能分享的幫助,
下面是一些代碼:
// Class runs in Thread #2: Prepares message data for Windows Form GUI display and passes to UI Thread #1
public class Aag_PrepDisplay
{
private Aag_PrepDisplay mAagPrep;
public Aag_PrepDisplay AagPrep
{
get { return mAagPrep; }
set { mAagPrep = value; }
}
// Thread #2: prepares message for Windows Form GUI display in UI Thread #1
public void PrepareDisplay(/*stuff*/)
{
mAagPrep = new Aag_PrepDisplay();
// does message prep stuff
SetOperation setOp1 = new SetOperation();
setOp1.FireEvent(mAagPrep); // call to UI Thread #1 method to fire event to update GUI; passes object with data
}
}
// UI Thread #1 class is the Windows Form. Displays and updates all textboxes.
public partial class SetOperation : Form
{
public event Action<object> OnChDet; // declared delegate object event that passes an object
public SetOperation()
{
InitializeComponent();
OnChDet += chDetDisplayHandler; // hooks handler to event
}
// Thread #1: accepts object w/data from Thread #2; Fires an event to update GUI Textbox(s)
private void FireEvent(Aag_PrepDisplay aagPrep)
{
OnChDet(aagPrep);
}
// UI Thread #1 event handler.
public void chDetDisplayHandler(object name)
{
// **** Problem: event is triggered and value assigned, but doesn't update the GUI window Textbox ********
actFreqChan1.Text = "402.5"; // this is only a test to see if event handler will update Textbox
// Next step: updateAll(name); // pass the object from Aag_PrepDisplay class
}
//Thread #1: update GUI Textbox values
public void updateAll(object name)
{
// this is where data from the Thread #2 AagPrep object will assign and update Textbox values
}
}
在問題線上放置一個斷點,然后告訴我們您所看到的。
在事件基礎架構中,它可能不會被調用並且問題仍然存在。 如果被調用,則問題出在“ Text
字段的設置器中。
在兩種情況下,缺陷都不是您認為的所在。
我會簡化代碼。 可能我缺少了一些東西,但是嘗試一下。
public partial class SetOperation : Form
{
public event Action<object> OnChDet;
public SetOperation()
{
InitializeComponent();
OnChDet += chDetDisplayHandler;
}
private void chDetDisplayHandler(object name)
{
ActFreqChan1.Text = "402.5";
}
}
然后,您可以使用以下命令簡單地觸發事件:
mySetOperationInstance.OnChDet(myNameObject);
問題是世衛組織將觸發該事件嗎? 這取決於您自己找出答案。 您必須將上述行放在某處。
據我所知,您不需要:
ChanEventArg
; ChDetHandler
; Aag_DisplayEvent
(這看起來完全錯誤); EventLaunch()
方法。 您唯一需要關心的是:
event
; 這樣做:制作代碼的備份副本,並嘗試簡化代碼。
如果對不起您,對不起,請恢復為您的備份。 否則,您會做得太多,而在某個地方,您對事件的准確分配失去了把握。
事件處理程序可能會拋出一個Exception
,該Exception
不會出現在UI上並保持潛在狀態。 以下代碼將防止創建控件的線程以外的其他線程拋出異常:
官方參考: MSDN上的InvokeRequired
類似的問題: 使用InvokeRequired與control.InvokeRequired
較長的解釋但確實很好: WinForms中有關線程安全的MSDN教程
將線程安全保護( InvokeRequired
等)包裝在事件處理程序中的此分配周圍:
actFreqChan1.Text = "402.5";
希望這對您有所幫助。 否則,您仍然可以回到這里。
謝謝pid。 當從線程1的SetOperation()中觸發該事件時,我回過頭來重新創建了更新文本框的代碼。事件處理程序更新了文本框。 然后,我嘗試從線程2的PrepareDisplay()調用線程1方法,並從線程1方法觸發事件。 事件處理程序不會更新文本框。 接下來,我將安全的線程調用代碼添加到Thread 1 SetOperation類。 文本框不會使用安全的線程調用代碼進行更新。 我將其從MSDN教程中刪除。 當我遍歷代碼流時,很難遵循它。 它在方法之間來回跳躍。 看來InvokeRequired給出了錯誤。 無論哪種情況,文本框都應更新為402.5。 您看到我放錯了什么或其他缺少的代碼嗎?
下面是我模擬的整個代碼。 再次感謝您願意為我提供一些指導。
namespace TstTxtBoxUpdate
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Aag_PrepDisplay aag_Prep1 = new Aag_PrepDisplay();
Thread AagPrepDisplayThread = new Thread(new ThreadStart(aag_Prep1.PrepareDisplay));
AagPrepDisplayThread.Start();
while(!AagPrepDisplayThread.IsAlive)
;
Thread.Sleep(1000);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new SetOperation());
}
}
}
namespace TstTxtBoxUpdate
{
// Thread 1: UI
public partial class SetOperation : Form
{
private string text;
public event Action<object> OnChDet;
delegate void SetTextCallback(string text);
private Thread demoThread = null;
public SetOperation()
{
InitializeComponent();
OnChDet += chDetDisplayHandler;
}
public void FireEvent(Aag_PrepDisplay aagPrep)
{
OnChDet(mName);
}
private void chDetDisplayHandler(object name)
{
this.demoThread = new Thread(new ThreadStart(this.ThreadProcSafe));
this.demoThread.Start();
}
private void ThreadProcSafe()
{
this.SetText("402.5");
}
private void SetText(string text)
{
if(this.actFreqChan1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
// TextBox NOT updated when event called from FireEvent() that was called from Thread 2 PrepareDisplay()
// TextBox IS updated when event called from Thread 1: SetOperation() or FireEvent()
this.actFreqChan1.Text = text;
}
}
}
}
namespace TstTxtBoxUpdate
{
// Thread 2: Data prepare
public class Aag_PrepDisplay
{
#region Fields
private Aag_PrepDisplay mAagPrep;
#endregion Fields
#region Properties
public Aag_PrepDisplay AagPrepDisp;
public Aag_PrepDisplay AagPrep
{
get { return mAagPrep; }
set { mAagPrep = value; }
}
#endregion Properties
#region Methods
public void PrepareDisplay()
{
mAagPrep = new Aag_PrepDisplay();
SetOperation setOp1 = new SetOperation();
setOp1.FireEvent(mAagPrep); // calls Thread 1 method that will fire the event
}
#endregion Methods
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.