blueworld's picture

How to know when GLControl is safe to use

I'm trying to use a GLControl in a windows form as described in Chapter 2 of the tutorial, but I'm having a hard time figuring out what to wait on to ensure that OpenGL has a context so it's safe to use.

If I wait on the containing form's Load event, I get an exception later ("No context is current in the calling thread") when I try to access GL functions (calling BeginInvoke on the form).
If I simply wait for 5 seconds, there's no problem accessing these functions, but this seems like a hack.
Tried waiting on the GLControl's Load event, but it seems never to be called. This is the relevant code for the form:

internal class Form1 : Form
{
        private GLControl m_glControl;
        public Form1()
        {
                Load += new EventHandler(Form1Loaded);
                m_glControl = new GLControl();
                m_glControl.Load += new EventHandler(GLControlLoaded);
        }
 
        public void GLControlLoaded(object sender, EventArgs e)
        {
                Console.WriteLine("GLControl Loaded");
        }
 
        private void Form1Loaded(object sender, EventArgs e)
        {
                Console.WriteLine("Form1 loaded");
                m_glControl.Width = this.Width;
                m_glControl.Height = this.Height;
                Controls.Add(m_glControl);
                m_glControl.Parent = this;
                Context = GraphicsContext.CurrentContext;
      		GL.MatrixMode(MatrixMode.Projection);
      		GL.LoadIdentity();
      		GL.Ortho(0, m_glControl.Width, 0, m_glControl.Height, -1, 1);
      		GL.Viewport(0, 0, m_glControl.Width, m_glControl.Height); 
        }

Am I missing something in hooking up the GLControl as a child of the form so that the Load event will actually be called? Is the GLControl's Load event the right thing to wait on to ensure it's safe to call GL?

Thanks!


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

You can check for the presence of an OpenGL context using the GraphicsContext.CurrentContext property.

You can use OpenGL functions once GLControl.IsHandleCreated returns true (the context is constructed during the HandleCreated event). This typically happens after the Load event of the parent Form, but before the Load event of the GLControl (are you positive GLControl.Load is hooked)?

If you wish more control over the context, you can call GLControl.CreateHandle() (this method is protected), or read the value of GLControl.Handle (this will call CreateHandle() automatically).

For example, this code should print non-null values:

using System.Windows.Forms;
using OpenTK;
 
class TestForm : Form
{
    GLControl glControl = new GLControl();
 
    public Form()
    {
       this.Load += (sender, e) =>
       {
           Console.WriteLine("TestForm.Load: {0}", GraphicsContext.CurrentContext);
           var dummy = glControl.Handle; // Forces creation of GLControl
           Console.WriteLine("TestForm.Load: {0}", GraphicsContext.CurrentContext);
        }           
        glControl.Load += (sender, e) =>
        {
            Console.WriteLine("GLControl.Load: {0}", GraphicsContext.CurrentContext);
        }
    }
}
objarni's picture

This must be some change in behaviour of OpenTK?

Assuming the context/GLControl was initialized on the Form.Load event used to be safe (OpenTK version 0.98 and older).

the Fiddler's picture

No, it was never safe to use GLControl in Form.Load.

objarni's picture

OK but at least it has worked for a year on my WinXP/Vista work/home projects.

What is the recommended way of "playing safe" on this issue? I mean what API is most stable to use? I want to add this information to the GLControl tutorial.

the Fiddler's picture

Use GLControl.Load().

blueworld's picture

Ok, I tried reading the value of the handle in the containing form's Load handler and the HandleCreated event still doesn't seem to be firing. Starting to wonder if something is hooked up wrong, though I've checked over the places where I hook up the events several times.

the Fiddler's picture

Please reduce the code to the minimum that reproduces the problem and attach it to an issue report.

blueworld's picture

I keep thinking that it must be something completely silly that I'm missing. I don't have a designer in the version of MonoDevelop I'm using, so I'm adding the control to the form programmatically and maybe I'm doing it wrong.

Also, can you call GLControl.Load() yourself? I tried calling it in my event handler for the loading of the containing form (in another class, outside the form and the control) and got a compilation error: "The event `System.Windows.Forms.UserControl.Load' can only appear on the left hand side of += or -= when used outside of the type `System.Windows.Forms.UserControl'(CS0070)" I apologize for all the silly questions, I'm experienced with .NET and C# development but new to Windows Forms.

I'm attaching a pared down demo of the issue where the events aren't firing. Maybe someone can see what I'm missing.

AttachmentSize
NoEventsDemo.cs2.59 KB
blueworld's picture

The solution I've come up with is to loop until GraphicsContext.CurrentContext is not null before I make GL calls. Still hacky, but it works consistently so far.

the Fiddler's picture

Interesting, I can confirm that GLControl.Load never occurs. Investigating.

To raise an event, you have to inherit from the Control and call the relevent OnXyz method. For example,

class CustomControl : GLControl
{
    public CustomControl()
    {
        OnLoaded(this, EventArgs.Empty);   // Raises the Load event.
    }
}