Application.DoEvents()在应用程序运行时不断调用?

时间:2011-03-13 13:44:33

标签: .net-3.5 windows-mobile compact-framework

我正在尝试为我的应用程序添加表单兑现模块,我实现了这个msdn示例:Form Stacking and Caching

对于那些无法下载示例的人,这是包含我所指代码的类:

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;
    }
}
}

Run()方法在应用程序运行时不断调用Application.DoEvents()。我发现很难相信这对应用程序来说是件好事。我很想听到有关此事的其他意见。感谢。

1 个答案:

答案 0 :(得分:1)

首先,您需要了解WinForms应用程序的工作原理。在Application.Run调用的深处,是一段代码,通常被称为消息泵。这是一个无限循环,调用GetMessage,TranslateMessage和DispatchMessage。实质上,Application.DoEvents调用该循环的一次循环。您正在查看的DoEvents循环只是执行此操作。

现在为什么,甚至需要这个电话,我不能诚实地说。这是非常糟糕的,因为我编写了代码,但在我的辩护中,这段代码已经差不多十年了,我几乎不记得上周我做了什么。

如果删除循环,会发生什么?我没有看到任何表明你会得到绘图工件或绘制失败的东西(这是添加调用的典型原因),但是这段代码也写成了aganst CF 1.0,所以很可能已经克服了运行时限制。

对于它的价值,我revisited and rewrote the code in 2009并且重写没有循环(或者甚至是Run方法)。

顺便说一下,我看到Push中有一个bug。 foreach循环有return而没有执行Monitor.Exit。我可能会重写该方法以使用lockfinally块来调用Monitor.Exit。