0

I'm trying to be able to access some controls in my main form from an other thread.

Let's consider this picture:

enter image description here

I want to Instantiate that control (It's a panel in my case) into the second thread.

My problem is that i have found a LOT of answers that just modifies a control (Set the text of a textbox for instance) and not be able to read/write it's properties like it's an object. (Delegates and stuff)

My current code: (Not working because i've created the panel in the other thread)

public partial class Main : Form
{
    Graphics g;

    Thread drawCanvasThread;

    int pos = 0;

    public Main()
    {
        InitializeComponent();
    }

    private void Main_Load(object sender, EventArgs e)
    {
        g = canvas.CreateGraphics();

        drawCanvasThread = new Thread(() => HandleCanvas(canvas));
        drawCanvasThread.Start();
    }

    private void HandleCanvas(Panel objCanvas)
    {
        Panel canvas = objCanvas;
        Point mousePos;
        while(true)
        {
            mousePos = canvas.PointToClient(Cursor.Position);

            //UPDATE CANVAS

            //DRAW CANVAS

            Thread.Sleep(17); //1000 / 17 ~~= 60
        }
    }

    private void Main_FormClosing(object sender, FormClosingEventArgs e)
    {
        drawCanvasThread.Abort();
    }
}

PS: The thread "How to update the GUI from another thread in C#?" doesn't really answers my question, because i want to read the object properties, and not only write. Though it's a very interesting thread.

Community
  • 1
  • 1
Riptide
  • 385
  • 7
  • 17
  • _"The thread 'How to update the GUI from another thread in C#?' doesn't really answers my question, because i want to read the object properties, and not only write"_ - you can still use thread marshalling techniques to read properties. However I think you should redesign your app because thread marshalling is **very expensive** to the point where it can be a significant hindrance to using threads in the first place –  Apr 06 '15 at 00:15
  • Hmm.. I don't know how to redesign it then.. Basically i'm making a level editor, and i want to make a canvas & a 'controls' part (http://i.stack.imgur.com/iIN8X.png). The thread was to update & draw the canvas.. I'm gonna find some advices on gamedev.. Thanks anyways. – Riptide Apr 06 '15 at 00:21
  • @Riptide Reading properties wouldn't be that big a deal. You just need to marshal those calls and do the actual reading from the UI thread more or less the same way you'd do the writing. – Craig Tullis Apr 11 '15 at 02:35

1 Answers1

0

EDITED

You don't want to "instantiate" the control into the other thread.

There are some differences if you're working with Winforms (Win32) vs WPF (Windows Presentation Foundation). The Win32 UI libraries ("Winforms") are not thread-safe. You'll get unpredictable results, memory leaks and outright crashes if you allow any thread other than the main UI thread to directly fiddle with controls.

The WPF UI library is thread-safe, on the other hand, but there are still plenty of issues to be aware of and I'm not trying to address them all in this short (I hope) answer. ;-)

You really don't even want access across a thread boundary to a reference to a control instance. What you want to do is signal the UI thread to do what you want. There's more than one way to skin that cat, and you'll want to do some research. But the basic idea is that you set some kind of shared state from the other thread that tells the UI thread to take action, or raise an event that executes on the UI thread, and you initiate your interaction with the control from that event handler. Look up concepts like a message pump. But what you almost definitely don't want to do is fiddle with the Windows message loop to "subclass" the forms and controls.

Other useful tools include the BackgroundWorker class, and the newer Tasks library. You should pick and use one or the other, but not both simultaneously. The general model is that you'll launch a task thread from your UI thread, and when it returns it will raise an event in the UI thread from where you can do useful work with the controls on your forms.

Craig Tullis
  • 9,939
  • 2
  • 21
  • 21
  • Thanks, i'm going to read on the Task lib. I meant to refer, not instanciate, you're right. – Riptide Apr 05 '15 at 23:49
  • _"You want access to a reference to the control from the other thread"_ - that's not correct. A worker thread marshals it's request over the _message pump_ to the UI thread who carries out the request to manipulate the control. It is the UI thread that does the work not the worker thread. It is not correct to think that the worker thread has a _"reference to the control"_ –  Apr 05 '15 at 23:59
  • _"Win32 isn't thread-safe, period"_ - do you mean `Win32 windows` or `GDI-related` functions because `Win32` is pretty broad and large parts of it **are thread safe**. How else to you think overlapped or IOCP operate? –  Apr 06 '15 at 00:01
  • 1
    @MickyDuncan I obviously only mean the UI portion of the Win32 API ("Winforms"). The poster is asking about controls on Windows forms. ;-) – Craig Tullis Apr 06 '15 at 02:43
  • Thanks Craig, maybe just revise that phrase slightly and all is good. :) –  Apr 06 '15 at 02:46
  • @MickyDuncan you're right about only letting the UI thread directly call into the controls, and I should clarify a little. There are multiple ways to signal the UI thread to do useful work, of course. – Craig Tullis Apr 06 '15 at 02:50