Sign in to follow this  
23yrold3yrold

[.net] C# and window not refreshing immediately

Recommended Posts

Mmmm, been a while since I posted here .... anyway ... I took up C# a while ago and I've been trying to figure out a strange problem, which is why my windows won't redraw immediately. Example: I open the left window using an option in the Window menu. The main window doesn't refresh the area where the menu opened. It'll refresh if I drag the smaller window onto it, but even then the refresh is always a step behind, and everything leaves a "trail" of gray. I switched to managed DirectX mostly for the speed, but also to see if it would correct this. No dice. :( I've tried calling every redraw, update, and invalidate function I can find, so not sure what I'm doing wrong. I decided to rip out the extra bits to get it down to a core of code I could post; here's the relevant bits of what I got. Anyone got some pointers?
        public bool InitializeDirect3D()
        {
            PresentParameters pps;

            try
            {
                pps = new PresentParameters(Program.maindevicecontext.PresentationParameters);
                pps.BackBufferCount = 1;
                pps.DeviceWindow = drawingwindow;
                pps.DeviceWindowHandle = drawingwindow.Handle;
                pps.BackBufferWidth = drawingwindow.Width;
                pps.BackBufferHeight = drawingwindow.Height;
                m_mainwindowswap = new SwapChain(Program.maindevicecontext, pps);

                pps = new PresentParameters(Program.maindevicecontext.PresentationParameters);
                pps.BackBufferCount = 1;
                pps.DeviceWindow = currenttiles;
                pps.DeviceWindowHandle = currenttiles.Handle;
                pps.BackBufferWidth  = currenttiles.Width;
                pps.BackBufferHeight = currenttiles.Height;
                m_currtilesswap = new SwapChain(Program.maindevicecontext, pps);

                return true;
            }
            catch (DirectXException e)
            {
                MessageBox.Show(e.ToString(), "Error from main window!!");
                return false;
            }
        }

        public MainWindow()
        {
            scrollx = scrolly = 0;
            InitializeComponent();

            PresentParameters pps = new PresentParameters();
            pps.Windowed = true;
            pps.SwapEffect = SwapEffect.Discard;
            Program.maindevicecontext = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, pps);

            if (this.InitializeDirect3D() == false)
            {
                MessageBox.Show("Could not initialize Direct3D.", "Error");
                return;
            }

            PaintBigWindow();
            PaintSmallWindow();
        }

        private void PaintBigWindow()
        {
            if (m_mainwindowswap.Disposed)
                return;

            Surface surf = m_mainwindowswap.GetBackBuffer(0, BackBufferType.Mono);
            surf.Device.SetRenderTarget(0, surf);

            // start drawing
            surf.Device.BeginScene();
            surf.Device.Clear(ClearFlags.Target, Color.Black, 1.0f, 0); // Clear the window

            // DirectX bits go here, commented out for now

            surf.Device.EndScene();
            m_mainwindowswap.Present();
        }

        private void PaintSmallWindow()
        {
            if (m_currtilesswap.Disposed)
                return;

            Surface surf = m_currtilesswap.GetBackBuffer(0, BackBufferType.Mono);
            surf.Device.SetRenderTarget(0, surf);

            // start drawing
            surf.Device.BeginScene();
            surf.Device.Clear(ClearFlags.Target, Color.Black, 1.0f, 0); // Clear the window

            // DirectX bits go here, commented out for now

            surf.Device.EndScene();
            m_currtilesswap.Present();
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            PaintBigWindow();
        }

        private void currenttiles_Paint(object sender, PaintEventArgs e)
        {
            PaintSmallWindow();
        }

        private void MainResize()
        {
            m_mainwindowswap.Dispose();
            m_currtilesswap.Dispose();

            // snip snip
            
            InitializeDirect3D();

            PaintBigWindow();
            PaintSmallWindow();
        }

        private void MainWindow_Resize(object sender, EventArgs e)
        {
            MainResize();
        }

        private void tileWindowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            smallwindow = new SmallWindow();

            smallwindow.Show();
        }

        private void MainWindow_Paint(object sender, PaintEventArgs e)
        {
            PaintBigWindow();
            PaintSmallWindow();
        }
    }
}

I'm coming back to this personal project after hacking at this problem for a while and then leaving it for a couple of months, so if you see something particularly odd, no, I don't remember why I did it ... if you need any more info let me know.

Share this post


Link to post
Share on other sites
Try calling Invalidate method on your Window after you've opened the menuitem (A bit harsh but maybe it works).

I don't know if their is an event that you've closed the menuitem, but you should try and find an event like that. In that event you force a redraw of your black windows.

Share this post


Link to post
Share on other sites
Sprinkle a few calls to Application.DoEvents and see if it fixes the issue.

Also, make sure that your new window is "owned" by the main window, because otherwise each window will steal events from the other one (WinForms is supposed to detect this and throw an exception but there are many ways to break the detection).

Share this post


Link to post
Share on other sites
There are several ways of accomplishing what you want to do. If your control is going to display continous animation, the most common way of resolving the problem is via the Application.Idle event. This event is triggered when the application thread has completed processing windows messages and is about to become idle. Because of this, the event is continously raised and makes a good candidate for forcing the updating of rendering code.


// Were yourControl is the control or form that you are drawing on.
Application.Idle += EventHandler( yourControl.OnApplicationIdle );

void OnApplicationIdle (object sender, EventArgs e)
{
// Forces the control to repaint itself. This will cause the OnPaint method to be called.
// Another option is to directly inject the DirectX rendering code here
// (Although the control and its child controls would not be redrawn).
Invalidate();
}





On a side note, Managed DirectX is now a deprecated project. Microsoft is no longer maintaining it. You should consider migrating to XNA or SlimDX.

Share this post


Link to post
Share on other sites
Oxidda: I've already tried peppering every event with Invalidate() and Refresh(), no effect. I'm figuring the problem is something more specific with a more elegant solution than that. :)

Fiddler: I don't think it's something that Application.DoEvents will fix; my code is doing very little worth waiting on. But checking that the children know who is the parent isn't a bad idea. I don't see anywhere the parent is explicitly assigned in the generated code. I'm going to have to figure out how C# sets/gets parents and check on that ...

Billr17: Yeah, no animation (yet). Again, I was hoping for a more elegant solution. I'm not interested in XNA right now because this isn't for a game, but I might look into SlimDX if I find this lacking, thanks.

Share this post


Link to post
Share on other sites
Quote:
Original post by 23yrold3yrold
Fiddler: I don't think it's something that Application.DoEvents will fix;


One thing to keep in mind is that the Application.DoEvents method allocates quite a bit of garbage that needs collected. Tom Miller had an interesting post quite a while ago on why you would not want to use this method in a render loop. Its probably still worth taking a look at: http://blogs.msdn.com/tmiller/archive/2003/11/07/57524.aspx

The solution I posted is what Microsoft generally recommends. Tom Miller had posted this as a solution for getting Managed DirectX working within Windows Forms back when he was still working on MDX. Also Microsoft used this same solution in thier official XNA examples for showing how to use XNA with Windows Forms.

From what I see, it appears that your control is properly redrawing itself. However, the DirectX surface is not being redrawn onto the control. Have you tried hooking the Invalidated event for the control your drawing on? That way you can force it to draw when the control becomes invalidated. Also, have you tried to set a break point in you paint event handlers to see if the code is ever hit when the control becomes invalidated?

Share this post


Link to post
Share on other sites
Playing with it now; Application.Idle works as intended but my whole application is flickering nastily, even when I'm not clearing to the background colour. I think the parent thinks it's supposed to refresh itself over the child window ...

Share this post


Link to post
Share on other sites
Quote:
Original post by 23yrold3yrold
Playing with it now; Application.Idle works as intended but my whole application is flickering nastily, even when I'm not clearing to the background colour. I think the parent thinks it's supposed to refresh itself over the child window ...


Are you invalidating the form each time the idle event is raised? Invalidating the form would cause the flickering you are seeing. If so, only invalidate the child controls you are drawing on.

Share this post


Link to post
Share on other sites
I think I found the problem; the Application.Idle doesn't fire if that dialog window is open ... for whatever reason. Confirmed by adding the MessageBox.Show() call; it spams my screen until I open that dialog. Gonna have to find a way to deal with that ...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this