【问题标题】:How to update the Windows Form Textbox values using Multiple threads如何使用多线程更新 Windows 窗体文本框值
【发布时间】:2014-01-28 22:06:37
【问题描述】:

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

下面是压缩代码的sn-p。我希望它能说明消息数据如何在 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);
        }
    }

【问题讨论】:

标签: c# multithreading forms event-handling


【解决方案1】:

您的问题与该主题的所有其他问题完全相同。有三种方法可以对 UI 线程的方法调用进行编组,虽然我没有详细阅读您的代码,但我看不出您在哪里使用它们中的任何一种。这就是问题所在。一种方法适用于 WinForms 窗体或控件中的代码,一种适用于 WPF 窗口和控件,而第三种方法适用于无法直接访问控件的 WinForms 或 WPF 应用程序中的代码。我已经演示了所有三个here。实施最适合您的情况。如果您希望表单或控件进行编组,则使用 ISynchronizeInvoke,如果您希望类在 UI 线程上引发事件,即使它本身不是 UI 元素,则使用 SynchronizationContext。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-19
    • 2022-08-23
    • 1970-01-01
    相关资源
    最近更新 更多