.NET Compact Framework:如何在运行代码之前确保表单可见?

时间:2010-01-20 15:13:58

标签: winforms performance user-interface compact-framework

我们的.NET Compact Framework应用程序设置了Model-View-Presenter。标准CF表单正在实现视图接口,并传递给演示者的构造函数。演示者通过调用view.Run()来告诉表单显示自己。然后视图会自动执行Show(),并且演示者再次接管,加载数据并将其填充到视图中。

问题是视图在控件返回到演示者之前没有完成显示。由于演示者代码在加载数据时会阻塞几秒钟,因此效果是表单在几秒钟内不可见。直到演示者完成数据加载后,表格才会变得可见,即使在演示者开始加载数据之前,表单上还会调用Show()。

在标准的Windows环境中,我可以在表单上使用.Shown事件......但是紧凑的框架没有这个,我找不到相应的。

有没有人知道一个偶数,一个pinvoke,或其他方式让我的表单在演示者的一些代码开始之前完全可见?在这一点上,我可以使用表单调用演示者并告诉演示者启动它的数据加载。

仅供参考 - 我们正在努力避免多线程,以减少复杂性和资源使用。

3 个答案:

答案 0 :(得分:2)

一般规则是:永远不会在UI线程上做任何阻止

Windows中的UI(以及Windows CE中的UI)具有异步性质。这意味着大多数API调用不一定会做他们应该做的任何事情。相反,它们会生成一系列事件,这些事件被放入事件队列中,然后由事件泵检索,事件泵本质上是在UI线程上运行的无限循环,逐个从队列中挑选事件,并处理它们

从上面可以得出结论,如果你在请求某个动作后继续在UI线程上做一些冗长的事情(即在你的情况下显示窗口),事件泵就无法继续挑选事件(因为你没有将控制权交还给它),因此,您要求的行动无法完成。

一般方法如下:如果你必须做复杂的数据转换/加载/准备/无论什么,在一个单独的线程上做,然后使用Control.BeginInvoke将一个委托注入UI线程,并触摸实际来自该委托内部的UI控件。

尽管你对多线程带来的“复杂性”的非理性恐惧,但是很少有人害怕。这里有一个例子来说明这一点:

public void ShowUI()
{
    theForm = new MyForm();
    theForm.Show();

    // BeginInvoke() will take a new thread from the thread pool 
    // and invoke our delegate on that thread
    new Action( PrepareData ).BeginInvoke(null,null);
}

public void PrepareData()
{
    // Prepare your data, do complex computation, etc.

    // Control.BeginInvoke will put our delegate on the UI event queue
    // to be retrieved and executed on the UI thread
    theForm.BeginInvoke( new Action( PutDataInTheForm ) );
}

public void PutDataInTheForm()
{
    theForm.textBox1.Text = "data is ready!";
}

虽然您可以使用其他解决方案,但总体思路始终保持不变:如果您在UI线程上执行任何冗长操作,您的UI将“冻结”。当您在屏幕上添加新的UI元素时,它甚至不会重绘自身,因为重绘也是一个异步过程。

因此,你必须在一个单独的线程上完成所有复杂和冗长的东西,并且只做简单,小,保证在UI线程上运行快速的东西。真的没有别的选择。

希望这有帮助。

答案 1 :(得分:1)

如果您的关键问题是在您的演示者数据加载方法完成之前表单不会被绘制,并且您在Form_Load中调用this.Show(),请在此之后直接尝试使用Application.DoEvents()。 Show()强制/允许表单绘制。

protected void Form_Load(blah blah blah)
{
   this.Show();
   Application.DoEvents();

   ... data loading methods ...
}

答案 2 :(得分:0)

如果你不想创建另一个线程(尽管必须以某种方式处理几秒钟)。 您可以使用激活的事件。因为它会在激活表单时触发,所以表单需要一个boolean local来检查表单是否已经首次创建。 另一个选择是在完成表单呈现后立即断开事件处理程序。