简体   繁体   English

为什么我的事件处理程序不更新Windows窗体文本框?

[英]Why doesn't my event handler update my Windows Form textbox?

Can anyone explain or show why my event handler doesn't update my Windows Form textbox? 谁能解释或显示为什么我的事件处理程序不更新Windows窗体文本框? I have put the event handler in the UI thread to update a textbox in my GUI window. 我将事件处理程序放在UI线程中,以更新GUI窗口中的文本框。 An EventLaunch method in my UI Thread #1 SetOperation class initiates an event. 我的UI线程#1 SetOperation类中的EventLaunch方法启动一个事件。 The UI Thread #1 SetOperation class, OnChDetDisplay event handler completes but the Window Form textbox doesn't update to the assigned value. UI线程#1 SetOperation类OnChDetDisplay事件处理程序完成,但“窗口窗体”文本框未更新为分配的值。 What am I missing to tie the event and handler to updating the textbox? 将事件和处理程序与更新文本框联系在一起时,我缺少什么?

Thanks for any help anyone can share, 感谢任何人都能分享的帮助,

Below is some code: 下面是一些代码:

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

Put a breakpoint on the problem line and tell us what you see. 在问题线上放置一个断点,然后告诉我们您所看到的。

Probably it won't get called and the problem is upwards, in the event infrastructure. 在事件基础架构中,它可能不会被调用并且问题仍然存在。 If it gets called, the problem is in the Text field's setter. 如果被调用,则问题出在“ Text字段的设置器中。

In both cases, the defect is not where you think it is. 在两种情况下,缺陷都不是您认为的所在。

I'd simplify the code. 我会简化代码。 Probably I'm missing something but I'm giving this a try. 可能我缺少了一些东西,但是尝试一下。

public partial class SetOperation : Form
{
    public event Action<object> OnChDet;

    public SetOperation()
    {
        InitializeComponent();
        OnChDet += chDetDisplayHandler;
    }

    private void chDetDisplayHandler(object name)
    {
        ActFreqChan1.Text = "402.5";
    }
}

You can then fire the event simply with: 然后,您可以使用以下命令简单地触发事件:

mySetOperationInstance.OnChDet(myNameObject);

The question is WHO will fire the event? 问题是世卫组织将触发该事件吗? This is up to you to find out. 这取决于您自己找出答案。 You'll have to put the above line somewhere. 您必须将上述行放在某处。

As far as I can tell, you don't need to have: 据我所知,您不需要:

  • ChanEventArg ; ChanEventArg ;
  • ChDetHandler ; ChDetHandler ;
  • Aag_DisplayEvent (this looks completely wrong); Aag_DisplayEvent (这看起来完全错误);
  • EventLaunch() method. EventLaunch()方法。

The only thing you should care about is: 您唯一需要关心的是:

  • having an event ; 发生event ;
  • attaching a handler; 附加处理程序;
  • invoking it with parameters when need be. 需要时使用参数调用它。

Do this: make a backup copy of your code and try to simplify. 这样做:制作代码的备份副本,并尝试简化代码。

If it doesn't help I'm sorry, revert to your backup. 如果对不起您,对不起,请恢复为您的备份。 Otherwise you have done way too much and somewhere you've lost your bearings about how exactly the event is dispatched. 否则,您会做得太多,而在某个地方,您对事件的准确分配失去了把握。

Probably the event handler throws an Exception that doesn't emerge to the UI and remains latent. 事件处理程序可能会抛出一个Exception ,该Exception不会出现在UI上并保持潜在状态。 The following code will prevent other threads than the one creating the control from throwing exceptions: 以下代码将防止创建控件的线程以外的其他线程抛出异常:

The official reference: MSDN on InvokeRequired 官方参考: MSDN上的InvokeRequired

Similar question: Using InvokeRequired vs control.InvokeRequired 类似的问题: 使用InvokeRequired与control.InvokeRequired

The longer explanation but really good: MSDN tutorial on Thread-Safety in WinForms 较长的解释但确实很好: WinForms中有关线程安全的MSDN教程

Wrap the thread safety protection ( InvokeRequired and so on) around this assignment inside the event handler: 将线程安全保护( InvokeRequired等)包装在事件处理程序中的此分配周围:

actFreqChan1.Text = "402.5";

I hope this will help you out. 希望这对您有所帮助。 Otherwise you can still come back here. 否则,您仍然可以回到这里。

Thanks pid. 谢谢pid。 I went back and recreated the code to update the Textbox, when the event is fired from within the SetOperation() of Thread 1. The event handler updates the Textbox. 当从线程1的SetOperation()中触发该事件时,我回过头来重新创建了更新文本框的代码。事件处理程序更新了文本框。 I then tried to call a Thread 1 method from PrepareDisplay() of Thread 2 and fire the event from the Thread 1 method. 然后,我尝试从线程2的PrepareDisplay()调用线程1方法,并从线程1方法触发事件。 The event handler doesn't update the Textbox. 事件处理程序不会更新文本框。 Next, I added the safe thread-call code to Thread 1 SetOperation class. 接下来,我将安全的线程调用代码添加到Thread 1 SetOperation类。 The Textbox doesn't update with the safe thread-call code. 文本框不会使用安全的线程调用代码进行更新。 I took it right out of the MSDN tutorial. 我将其从MSDN教程中删除。 It was hard to follow the code flow when I stepped thru it. 当我遍历代码流时,很难遵循它。 It jumped back and forth between methods. 它在方法之间来回跳跃。 It appeared the InvokeRequired gave a false. 看来InvokeRequired给出了错误。 In either case, the Textbox should be updated to 402.5. 无论哪种情况,文本框都应更新为402.5。 Do you see something that I misplaced or other missing code? 您看到我放错了什么或其他缺少的代码吗?

Below is the entire code that I simulated. 下面是我模拟的整个代码。 Thanks again for your willingness to tutor me on some of this. 再次感谢您愿意为我提供一些指导。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM