任何人都可以解释或说明为什么我的事件处理程序不会更新我的Windows窗体文本框吗?我已将事件处理程序放在UI线程中以更新GUI窗口中的文本框。我的UI线程#1 SetOperation类中的EventLaunch方法启动一个事件。 UI Thread#1 SetOperation类,OnChDetDisplay事件处理程序完成,但Window Form文本框不会更新为指定的值。我错过了将事件和处理程序绑定到更新文本框的内容?
感谢任何人都可以分享的帮助,
以下是一些代码:
// 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
}
}
答案 0 :(得分:0)
在问题专栏上设置一个断点并告诉我们你看到了什么。
在事件基础设施中,可能不会被调用,问题也会出现问题。
如果它被调用,则问题出在Text
字段的setter中。
在这两种情况下,缺陷都不在您认为的位置。
我会简化代码。可能我错过了一些东西,但我试试看。
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);
问题是 WHO 会解雇这个事件吗?这取决于你找出答案。 你必须把上面的行放在某个地方。
据我所知,你不需要:
ChanEventArg
; ChDetHandler
; Aag_DisplayEvent
(这看起来完全错误); EventLaunch()
方法。你唯一应该关心的是:
event
; 执行此操作:制作代码的备份副本并尝试简化。
如果它没有用,我很抱歉,还原到您的备份。否则你已经做得太多了,而且你已经失去了关于如何发送事件的方式。
答案 1 :(得分:0)
事件处理程序可能抛出一个Exception
,它不会出现在UI中并保持潜伏状态。以下代码将阻止除创建控件的其他线程抛出异常:
类似的问题:Using InvokeRequired vs control.InvokeRequired
解释时间较长但非常好:MSDN tutorial on Thread-Safety in WinForms
在事件处理程序内围绕此分配包装线程安全保护(InvokeRequired
等):
actFreqChan1.Text = "402.5";
我希望这会帮助你。否则你仍然可以回到这里。
答案 2 :(得分:-1)
谢谢pid。当事件从线程1的SetOperation()内部触发时,我返回并重新创建了更新文本框的代码。事件处理程序更新了文本框。然后我尝试从线程2的PrepareDisplay()调用Thread 1方法并从Thread 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
}
}