开发者

Application.DoEvents() called constantly while application is running?

I was trying to add a form cashing module for my application and i implemented this msdn sample: Form Stacking and Caching

For those who cannot download the sample, this is the class that contains the piece of code i'm referring to:

using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Threading;

namespace GUIFramework {
    public class FormStack : CollectionBase {
        private System.Collections.ArrayList stack = new ArrayList();

    public void Run() {
        do {
            System.Windows.Forms.Application.DoEvents();
        } while(List.Count > 0);
    }

    public void Stop() {
        // nicely destroy each Form
        foreach(StackForm sf in List) {
            sf.Dispose();
        }
        // clear the list to kill the message pump in Run()
        List.Clear();
    }

    public void Push(Type FormType) {
        // only allow 1 Push at a time to maintain cache and stack itegrity
开发者_运维技巧        Monitor.Enter(this);

        foreach(StackForm sf in List) {
            if(sf.GetType().Name.Equals(FormType.Name)) {
                // form is cached so display cached version
                sf.Visible = true;

                // add it to the stack
                stack.Add(FormType.Name);

                return;
            }
        }

        // the Form wasn't cached, so create it
        StackForm form = Preload(FormType);

        // display it
        form.Visible = true;

        // add a close event handler
        form.FormClosed += new FormClose(form_FormClosed);

        // add it to the stack
        stack.Add(FormType.Name);

        Monitor.Exit(this);
    }

    public StackForm Preload(Type FormType) {
        StackForm form = (StackForm)Activator.CreateInstance(FormType);

        // get data on a separate thread
        form.LoadData();

        // build the form
        form.InitializeComponent();

        // wait for the data thread to finish
        form.threadRunning.WaitOne();

        // now populate the controls with any retrieved data
        form.Populate();

        form.MinimizeBox = false;  // required to get close event on PPC!

        // add it to the cache
        List.Add(form);

        return form;
    }

    public void Pop(uint FormsToPop) {
        if(stack.Count <= FormsToPop) {
            throw new Exception("You cannot Pop the entire stack!");
        }
        else {
            // remove from stack but not cache
            for(int i = 0 ; i < FormsToPop ; i++) {
                stack.RemoveAt(stack.Count - 1);
            }

            foreach(StackForm sf in List) {
                // find the last form in the stack
                if(sf.GetType().Name.Equals(stack[stack.Count - 1])) {
                    // make it visible
                    sf.Visible = true;
                }
            }
        }
    }

    private void form_FormClosed() {
        Pop(1);
    }

    public override string ToString() {
        string message = "There are " + List.Count.ToString() + " forms cached\r\n";
        message += "Stack contents:";

        for(int i = stack.Count - 1 ; i >= 0 ; i--) {
            message += "\r\n" + stack[i].ToString();
        }

        return message;
    }
}
}

The Run() method is calling constantly Application.DoEvents() while the application is runnning. I find it hard to believe that this is a good thing for the application. I'd love to hear other opinions about this. Thanks.


First you need to understand how WinForms apps work in general. Way down deep in the bowels of the Application.Run call is a piece of code often referred to as a message pump. This is an infinite loop that is calling GetMessage, TranslateMessage and DispatchMessage. Application.DoEvents, in essence, calls for once cycle of that loop. The DoEvents loop you're looking at would simply be doing this operation.

Now why, exactly, that call is even needed I can't honestly say. That's pretty bad since I wrote the code, but in my defense, this code is nearly a decade old and I can barely remember what I did last week.

If you remove the loop, what happens? I'm not seeing anything that indicates that you'd get drawing artifacts or failures to draw (which is the typical reason for adding the call), but this code was also written aganst CF 1.0, so it may well have been to overcome a runtime limitation.

For what it's worth, I revisited and rewrote the code in 2009 and the rewrite doesn't have the loop (or even a Run method for that matter).

BTW, there's a bug in Push that I see. The foreach loop has a return without doing a Monitor.Exit. I'd probably rewrite that method to use a lock or a finally block to call Monitor.Exit.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜