从在C#中运行循环UDP侦听的独立线程更新多文本框

本文关键字:线程 独立 更新 文本 运行 循环 UDP 从在 | 更新日期: 2023-09-27 18:22:23

我使用的是C#.net 4.0 VS 2010。

我得到了一个表单中的代码,它基本上在表单加载时添加了一个Task,以便运行UDP侦听器(在无限循环中)。每当监听器从UDP套接字中得到一些东西时,我都会在多行文本框(this.textBox4.Text)中添加一行和消息

然而,我得到了一个异常,说"跨线程操作无效:"Contol‘textBox4’是从创建它的线程以外的线程访问的

我不想仅仅为了传递值而结束循环。有办法做到这一点吗?这是我的代码:

    //main form load menu
    private void frm_Menu_Load(object sender, EventArgs e)
    {
        Task<int> Listening = DoWorkAsync(1, "OpenYourEars");
        .... // more code here                      
    }
    //async function
    public Task<int> DoWorkAsync(int milliseconds, string WhatToDo)
    {
        return Task.Factory.StartNew<int>(() =>
        {
            if (WhatToDo == "OpenYourEars")
                goListening();
            ... // more codes here
            return 1;
        });
    }
   //Listening on UDP socket
    public void goListening()
    {
        bool done = false;
        UdpClient listener = new UdpClient(listenPort);
        IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, listenPort);
        string received_data;
        byte[] receive_byte_array;
        try
        {
            while (!done)
            {
                receive_byte_array = listener.Receive(ref groupEP);
                received_data = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);
                // display on TextBox4
                this.textBox4.Text = "a'r'nb";
                this.textBox4.Text = received_data.ToString().Trim();
            }
        }
        catch (Exception e)
        {
            //gives "Contol 'textBox4' accessed from a thread other than 
            //the thread it was created on." when receiving a message.
            MessageBox.Show(e.ToString());
        }
        listener.Close();
    }

版本2-在@cremor和@George87的回答之后

    private void frm_Menu_Load(object sender, EventArgs e)
    {
        MyValue = "Menu,7";
        Task<int> Listening = DoWorkAsync(1, "OpenYourEars");
        .... // more code here                      
    }
    private Task<int> DoWorkAsync(int milliseconds, string WhatToDo)
    {
        return Task.Factory.StartNew<int>(() =>
        {
            if (WhatToDo == "OpenYourEars")
                goListening();
            .... // more codes here
            return 1;
        });
    }
    //Listening
    private void goListening()
    {
        bool done = false;
        UdpClient listener = new UdpClient(listenPort);
        IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, listenPort);
        string received_data;
        byte[] receive_byte_array;
        try
        {
            while (!done)
            {
                receive_byte_array = listener.Receive(ref groupEP);
                received_data = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);
                string aa = received_data.ToString().Trim();
                if ( aa != "")
                {
                    SetText("a'r'nb");
                    SetText(received_data.ToString().Trim());
                    aa = "";
                }
            }
        }
        catch (Exception e)
        {
            MessageBox.Show(e.ToString());               
        }
        listener.Close();
    }
    private delegate void SetTextCallback(string text);
    private void SetText(string text)
    {
        try
        {
              if (this.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.BeginInvoke(d, new object[] { text });
            }
            else
            {
                SetText(text);
            }
            this.textBox4.Text = text;
        }
         catch (Exception e)
         {
             MessageBox.Show(e.ToString());
         }
    }
    ....

从在C#中运行循环UDP侦听的独立线程更新多文本框

UI控件只能由创建它们的线程更改。您需要检查InvokeRequired(WinForms)或Dispatcher.CheckAccess()(WPF),然后调用Invoke/BeginInvoke

通常在使用c#和使用多线程时,应该使用委托来使事情正常工作,而不违反跨线程政治。换句话说,不允许从其他线程使用在一个线程中定义的对象。要实现这一点,您应该使用委托来强制拥有线程为调用线程执行任务。

代替:

  // display on TextBox4
  this.textBox4.Text = "a'r'nb";

你可以使用这个:定义以下方法:

delegate void SetTextCallback(string text);
private void SetText(string text)
{
   if (this.InvokeRequired)
   {
      SetTextCallback d = new SetTextCallback(SetText);
      this.Invoke(d, new object[] { text });
   }
   else
   {
      SetText(text);
   }
   this.textBox1.Text = text;     
}

并像这个一样从头开始呼叫他们

SetText("a'r'nb");

您可以尝试更改异步函数以使用当前同步上下文

 return Task.Factory.StartNew<int>(() =>
    {
        if (WhatToDo == "OpenYourEars")
            goListening();
        return 1;
    },
    new CancellationToken(),
    TaskCreationOptions.None, 
    TaskScheduler.FromCurrentSynchronizationContext());