Search code examples
c#wpfmultithreadingwinformssharpgl

C#: WinForms/WPF Render Loop


I want to make a render loop to render on a WPF Window or a WinForm. Therefore I want to use SharpGL (https://sharpgl.codeplex.com/). To make my loop I made a thread:

    public void Run()
    {
        IsRunning = true;
        this.Initialize();

        while (IsRunning)
        {
            Render(/* arguments here */);
            // pausing and stuff
        }

        Dispose();
    }

In Render I want to send the Draw Calls to the GPU. So far there is no problem. But Winforms and WPF need their own thread and loop. So I can't just create a Window and draw onto like in Java with LWJGL (https://www.lwjgl.org/), which I used before. I have to start another thread, that runs the Form in an Application (I cut out error handling to make it short):

    [STAThread]
    private void HostWinFormsApplication()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(true);

        // get Display
        Display = Engine.MainModule.Resolve<IDisplay>();
        Display.Initialize();
        Display.Closing += (s, e) => Stop();

        Application.Run(Display as Form);
    }

When my Renderer wants to access the OpenGL-Control on my Form and use it, an error occurs, as WinForms (and WPF) don't want their Controls to be manipulated by other Threads. So maybe an Invoke is an option, but this would delay my drawcalls and become a bottleneck. A timer isn't an option, too, as it isn't accurate and unflexible... And I simply don't like it. And doing everything inside the Window Code may be possible, but I want an application being independent of its Display, so that it can be changed. It should be an application having a Display not a Display running an application. In LWJGL I just had the possibility to create and initialize a Display and then simply use it. The only thing to consider was updating it and everything went fine. So I just want to create a Window in my render thread and draw onto. If I do it this way, the window just gets unusable and greyish as it needs this .Net-Loop. Is there any possibility to realize that or does anybody know another way to create Windows? Can I handle the window loop manually?

Any idea is welcome.

If there would be a way to do this with a WPF Window it would be awesome. Then I could have an OpenGL Control and all WPF-Stuff to make an Editor!


Solution

  • The solution was to call

    Application.DoEvents();
    

    in my Render Loop manually, as someone told me. So I didn't had to use Application.Run and were able to use my Form in the thread of the loop:

    public void Run()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(true);
    
        IsRunning = true;
        this.Initialize();
    
        MyForm = new CoolRenderForm();
        MyForm.Show();
    
        while (IsRunning)
        {
            Render(/* arguments here */);
            Application.DoEvents();
            // refresh form
            // pausing and stuff
        }
    
        Dispose();
    }