如何使用多个线程更新Windows窗体文本框值

时间:2014-01-28 22:06:38

标签: c# multithreading forms event-handling

这个问题与以前类似的问题不同。我还没有从他们那里找到我的问题的答案。我正在运行2个线程。线程#2接收消息,从中解析数据并准备在Windows窗体GUI中显示。线程#1运行Windows窗体GUI显示并更新其中的文本框值。我在除SetOperations类之外的两个不同的类中创建了一个事件和事件处理程序。 SetOperations是我的表单所在的类。我的代码编译并运行没有错误。我的事件似乎触发,事件处理程序似乎接收数据。我的文本框参数值也似乎已分配。我的问题是,当事件处理程序结束时,我没有看到文本框值更新。

以下是精简代码片段。我希望它说明了如何在GUI显示的类之间传递消息数据。我是C#新手所以请原谅我的一些无知。有没有人有一个我忽略的建议?事件处理程序是否需要位于SetOperations类或其他位置才能更新文本框值?

感谢您提供任何人可以分享的建议。

static class Program
    {
        // The main entry point for the application.
        [STAThread]
        static void Main()
        {
            Aag_Listen AagListen1 = new Aag_Listen();

            Trace.WriteLine("Application:  Thread #1 and #2: about to start");
            // starts Thread #2 where the Aag (server) listens for the Lru (client) message
            Thread AagListenThread = new Thread(new ThreadStart(AagListen1.ListenForLru));

            AagListenThread.Start();

            while(!AagListenThread.IsAlive)
                ;
            Thread.Sleep(3000);

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Application.Run(new SetOperation());    // this runs in Thread #1
        }
    }


    // Class is the beginning of Thread #2:  Aag (server) listens for Lru (client) incoming message
    // Gets the message data; calls to prepare it to be displayed by GUI; It then responds to the Lru
    // 1) listens for the Lru msg, accesses and reads it into an object
    // 2) passes the object with the message string to the AagPrepDisplay class
    public class Aag_Listen
    {
        #region Fields
        private Aag_Listen mAagListen2;
        private string lruString;
        internal Aag_PrepDisplay AagPrepDisplay;    // need external access by Thread #1
        #endregion Fields

        #region Properties
        public Aag_Listen AagListen2
        {
            get { return mAagListen2; }
            set { mAagListen2 = value; }
        }
        public string LruString
        {
            get { return lruString; }
            set { lruString = value; }
        }   
        #endregion Properties

        #region Methods

        // Aag (server) begins to listen for a Lru (client) message
        public void ListenForLru()
        {
            AagShowRequestData();
        }

        // Aag listener reads status of message data sent
        public void AagShowRequestData()
        {
            mAagListen2 = new Aag_Listen();

            this.AagPrepDisplay = new Aag_PrepDisplay();

            // this simulates updating each channel with message data as received from the Lru (client)
            int chan = 1;
            while(true)
            {
                    // display 405.1 and other message values
                    switch(chan)
                    {
                        case 1:
                            mAagListen2.LruString = "<tdrop><path sondeID=\"11024\"chanNum=\"1\"rxFreq=\"405.1\" />" +
                            "<sample frameNum=\"3440\"nsats=\"4\"gdop=\"25.5\"battery=\"5.58\"time=\"403892.500\"" +
                            "posx=\"-4738495.06\"posy=\"-2993107.15\"posz=\"-3044438.50\"gpsWeek=\"706\" /></tdrop>";
                            Trace.WriteLine("mAagListen2.LruString = " + mAagListen2.LruString);
                            chan = 3;
                            break;
                        case 2:
                            mAagListen2.LruString = "<tdrop><path sondeID=\"11024\"chanNum=\"3\"rxFreq=\"405.1\" />" +
                            "<sample frameNum=\"3440\"nsats=\"4\"gdop=\"25.5\"battery=\"5.58\"time=\"403892.500\"" +
                            "posx=\"-4738495.06\"posy=\"-2993107.15\"posz=\"-3044438.50\"gpsWeek=\"706\" /></tdrop>";
                            Trace.WriteLine("mAagListen2.LruString = " + mAagListen2.LruString);
                            chan = 4;
                            break;
                        default:
                            break;
                    }
                }
                AagPrepDisplay.PrepareDisplay(AagListen2);  // prepares data for Windows Form GUI display
            }
        }
        #endregion Methods
    }



        // Class runs in Thread #2:  Aag (server) prepares received Lru (client) message data for Windows Form GUI display 
    // 1) receives from Aag_Listen class message and determines if it's a correct message
    // 2) creates an object and extracts parameter values from message and assigns to object.
    public class Aag_PrepDisplay
    {
        #region Fields
        private string chanNum;
        private string receiveFreq;
        private DateTime date_time;
        private static int first;
        private static int last;

        private Aag_PrepDisplay mAagPrep;

        #endregion Fields

        #region Properties

        public Aag_PrepDisplay AagPrep
        {
            get { return mAagPrep; }
            set { mAagPrep = value; }
        }
        }
        public string ReceiveFreq
        {
            get { return receiveFreq; }
            set { receiveFreq = value; }
        }
        public string ChanNum
        {
            get { return chanNum; }
            set { chanNum = value; }
        }

        #endregion Properties

        #region Methods

        // begins extracting message parameters for Windows Form GUI display
        public void PrepareDisplay(Aag_Listen aagListen2)
        {
            mAagPrep = new Aag_PrepDisplay();
            Aag_DisplayEvent AagDisEvt1 = new Aag_DisplayEvent();

            bool Tdrop = aagListen2.LruString.Contains("tdrop");            // search for correct message
            if(!Tdrop)                              // reject string if not correct
                return;
            else
            {   //search message data string for channel parameters to prepare for Aag display

                // search for channel number from message; extract and save as string
                first = aagListen2.LruString.IndexOf("chanNum=\"") + "chanNum=\"".Length;
                last = aagListen2.LruString.IndexOf("\"rxFreq");
                String substring = new String('1', 1);
                mAagPrep.ChanNum = aagListen2.LruString.Substring(first, last - first);
                Trace.WriteLine("mAagPrep.ChanNum = " + mAagPrep.ChanNum);

                AagDisEvt1.ChDet += new ChDetHandler(OnChDetDisplay);   // hooks handler to event
                AagDisEvt1.ChDetDisplay(AagPrep);  // passes the object w/message parameters to AagDisplayEvent class to fire the event 
            }
        }

        // event handler called from Aag_DisplayEvent class
        public void OnChDetDisplay(object sender, ChanEventArg e)
        {
            SetOperation SetOp1 = new SetOperation();
            SetOp1.updateAll(AagPrep);
        }   //******* PROBLEM HERE:  WHY doesn't Windows Form actual frequency textbox update when this event closes?  PROBLEM HERE:*********

        #endregion Methods
    }


    // class handles the event argument that is the AagPrep class object containing all message parameters
    public class ChanEventArg : EventArgs
    {
        public object Name;
        public ChanEventArg(object name)
        {
            Name = name;
        }
    }

    public delegate void ChDetHandler(object sender, ChanEventArg e);   // declare delegate 

    // class is acting server that handles event notification
    public class Aag_DisplayEvent
    {
        public event ChDetHandler ChDet;    // delegate object reference declared

        // helper method to help call delegate object for event
        protected void OnChDet(ChanEventArg e)
        {
            if(ChDet != null)
            {
                ChDet(this, e);     // calls event
            }
        }

        // fires event by calling helper method 
        public void ChDetDisplay(object name)
        {
            OnChDet(new ChanEventArg(name));
        }
    }

    // this class is the Windows Form running in Thread #1.  It displays and updates all Window Form textboxes. 
    public partial class SetOperation : Form
    {

        public SetOperation()
        {
            Trace.WriteLine("Thread #1:  Set Operations Launched");
            InitializeComponent();
        }

        // updates the Aag (server) actual received frequency GUI display as received by the Lru (client) channel message
        public void updateActFreq(Aag_PrepDisplay aagPrep)
        {
            Trace.WriteLine("Update Actual Frequency Selected");    
            switch(aagPrep.ChanNum)
            {
                case "1":
                    Trace.WriteLine("Update ActFreqChan1 Selected");
                    ActFreqChan1.Text = aagPrep.ReceiveFreq;                // Lru (client) actual received frequency 
                    break;
                case "2":
                    Trace.WriteLine("Update ActFreqChan2 Selected");
                    ActFreqChan2.Text = aagPrep.ReceiveFreq;
                    break;
                case "3":
                    Trace.WriteLine("Update ActFreqChan3 Selected");
                    ActFreqChan3.Text = aagPrep.ReceiveFreq;            // PROBLEM: Why is this not updated in Windows Form textbox?
                    Trace.WriteLine("aagPrep.ReceiveFreq = " + aagPrep.ReceiveFreq);
                    Trace.WriteLine("ActFreqChan3.Text = " + ActFreqChan3.Text);  // NOTE: this does reflect the updated actual frequency.
                    break;
                default:
                    break;
            }           
        }

        // called from the Aag_DisplayEvent class event handler to update the actual frequency in Windows Form textboxes
        public void updateAll(Aag_PrepDisplay aagPrep)
        {
            Trace.WriteLine("Update All Selected"); 
            updateActFreq(aagPrep);
        }
    }

1 个答案:

答案 0 :(得分:0)

您的问题与此主题的其他问题完全一样。将方法调用封送到UI线程有三种方法,虽然我没有详细阅读你的代码,但我不知道你在哪里使用它们。这就是问题所在。一种方法适用于WinForms表单或控件中的代码,一种适用于WPF窗口和控件,而第三种适用于无法直接访问控件的WinForms或WPF应用程序中的代码。我已经演示了所有三个here。在您的情况下实施最合适的。如果您希望表单或控件执行编组,那么使用ISynchronizeInvoke,如果您希望类在UI线程上引发事件,即使它不是UI元素本身,也请使用SynchronizationContext。