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

时间:2014-01-29 22:38:12

标签: c# events user-interface

任何人都可以解释或说明为什么我的事件处理程序不会更新我的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
        }
    }

3 个答案:

答案 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中并保持潜伏状态。以下代码将阻止除创建控件的其他线程抛出异常:

官方参考:MSDN on InvokeRequired

类似的问题: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
    }
}