簡體   English   中英

為什么我的事件處理程序不更新Windows窗體文本框?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM