-1

This question is different from previous similiar questions. I haven't yet found an answer to my question from them. I am running 2 threads. Thread #2 receives a message, parses data from it and prepares it for display in the Windows Form GUI. Thread #1 runs the Windows Form GUI display and updates the Textbox values in it. I have created a event and event handler in two different classes other than the SetOperations class. SetOperations is the class that my Form is located. My code compiles and runs without errors. My event appears to fire off and the event handler appears to receive the data. My parameter values for the textboxes also appear to be assigned. My problem is that I don't see the textbox values updated when the event handler is concluded.

Below is a snippet of condensed code. I hope it illustrates how the message data is passed between classes for the GUI display. I'm a C# novice so please excuse some of my ignorance. Does anyone have a suggestion what I've overlooked? Does the event handler need to be located in the SetOperations class or elsewhere for the textbox values to be updated?

Thank you for recommendations anyone can share.

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);
        }
    }
Kent
  • 59
  • 1
  • 7
  • You should trim that "snippet" a bit. – rae1 Jan 28 '14 at 22:13
  • Your Thread 1 is the UI thread and has some specific considerations, have a look at this answer. http://stackoverflow.com/questions/661561/how-to-update-the-gui-from-another-thread-in-c – Tony Hopkinson Jan 28 '14 at 22:36

1 Answers1

0

Your question is exactly like every other question on this topic. There are three ways to marshal a method call to the UI thread and, while I haven't read your code in detail, I don;t see where you're using any of them. That is the issue. One method applies to code in WinForms forms or controls, one applies to WPF windows and controls while the third applies to code in a WinForms or WPF app that doesn't have direct access to a control. I have demonstrated all three here. Implement whichever is most appropriate in your case. If you want a form or control to do the marshalling then use ISynchronizeInvoke and if you want a class to raise an event on the UI thread even though it's not a UI element itself then use SynchronizationContext.

jmcilhinney
  • 50,448
  • 5
  • 26
  • 46