Access control element from static thread function

2019-06-14 10:39发布

问题:

I ve read lots of information about this stuff and i tried this:

class Server
{
... 
  public Server(int Port, ListBox ex_lb, PictureBox ex_pb)
  {
    ServerWork = new Thread(() => ServerFunction(Listener, ex_lb, ex_pb));
    ServerWork.Start();
  }
  static void ServerFunction(TcpListener ex_listener, ListBox ex_lb, PictureBox ex_pb)
  {
    //and any access to ex_lb throws exception, didnt debug to access to ex_pb
  }
}

this:

private static IncomingDataClass g_IDC = new IncomingDataClass();

private class IncomingDataClass
{
  static string data = "";
  public string Data
  {
    get { return data; }
    set { 
      data = value;
      SomeEvent(this,null,data);
    }
  }            
}

void IncomingDataClass_SomeEvent(object sender, EventArgs e, string ex_data)
{
  if (ex_data.Contains("listbox"))
  {
    ex_data = ex_data.Remove(ex_data.IndexOf("listbox"), "listbox".Length);
    listBox1.Items.Add(ex_data);
  }
}

delegate void MyEventHandler(object sender, EventArgs e, string ex_data);
static event MyEventHandler SomeEvent;
// in form load event
SomeEvent += IncomingDataClass_SomeEvent;
class Server
{
... 
  public Server(int Port, ListBox ex_lb, PictureBox ex_pb)
  {
    ServerWork = new Thread(() => ServerFunction(Listener));
    ServerWork.Start();
  }
  static void ServerFunction(TcpListener ex_listener)
  {
    //and any change of g_IDC.Data throws exception here
  }
}

this:

private static ListBox listBox1 = new ListBox();

private void Form1_Load(object sender, EventArgs e)
{
  ...
  listBox1.FormattingEnabled = true;
  listBox1.Location = new System.Drawing.Point(12, 256);
  listBox1.Name = "listBox1";
  listBox1.Size = new System.Drawing.Size(258, 108);
  listBox1.TabIndex = 6;
  Controls.Add(listBox1);
}
//anyways, even if i create new ListBox lb = listBox1 in ServerFunction(..), it throws System.InvalidOperationException => Access attempt to listBox1 not from thread where is was created.

What do i do wrong? I thought that creating static control is an ultimate problem solve for this, but even this doesnt work...

回答1:

If I remember correctly in order to update the UI from another thread you need to use this invocation:

this.Invoke((MethodInvoker)delegate
    {
        MethodForUpdatingUI();
    });

This will start MethodForUpdatingUI() from the UI thread, enabling you to access the controls.

So, for use this in your code I'll try to change IncomingDataClass_SomeEvent:

void IncomingDataClass_SomeEvent(object sender, EventArgs e, string ex_data)
{
        this.Invoke((MethodInvoker)delegate
        {
            UpdateListBox(ex_data);
        });
}

UpdateListBox(string ex_data)
{
  if (ex_data.Contains("listbox"))
  {
    ex_data = ex_data.Remove(ex_data.IndexOf("listbox"), "listbox".Length);
    listBox1.Items.Add(ex_data);
  }
}

Please feel free to correct me if this is not the case you are asking for or this is a bad pratice. I've not tested the code.



回答2:

You can only manipulate UI controls from UI thread. It doesn't matter if those controls are static or not, afaik. Use Dispatcher object or SynchronizationContext object to modify controls from different thread.