2009-11-11 55 views
0

我有一个Windows窗体(C#)项目,其中有多个组合框/列表框等​​等,当窗体加载时填充。当窗体加载时延迟加载组合框

的问题是,组合框/列表框的加载缓慢,因为当窗体试图显示整个窗体不显示,直到所有的控制都被填充装载完成。这在某些情况下可能是20+秒。

如果有一个Form_finished_loaded类型的事件我可以把我的代码放在那里,但是我找不到在完成绘制基本控件之后触发的事件。

虽然我有一个要求 - 加载必须在主线程中完成(因为我从非线程友好的COM应用程序中获取项目)。

我发现了一个潜在的解决方案,但也许有更好的方法? 我可以在创建表单时创建一个System.Timer.Timer,并在大约1秒钟后调用第一个Tick,然后从该tick中填充列表。这使得表格有足够的时间在开始填充列表之前显示。

有没有人有任何其他技巧如何延迟加载的控制?

回答

6

存在Shown event“只要首次显示表单就会发生”。您也可以使用BeginUpdate and EndUpdate函数更快地填充组合框。

+1

+1为BeginUpdate/EndUpdate提示。 – 2009-11-11 16:10:16

+0

是不是BeginUpdate,EndUpdate用于在将大量项目顺序加载到控件中时挂起绘画,而不是用于长时间运行的过程?显示事件为+1。 – 2009-11-11 16:46:56

+0

得到它的工作! 当添加巨大的集合时,BeginUpdate/EndUpdate产生了巨大的差异。高达10倍的改进。 – 2009-11-11 22:40:55

0

您可以从调用COM组件的Web服务获取数据吗?

这样,您可以在开始时显示锁定窗体上的空控件,使异步调用获取数据,并在返回时填充相应的组合,并且一旦所有组合都加载完毕,就可以解锁窗体用户使用。

0

您可以听取VisibleChanged事件,并且您首次将您的初始化代码设置为真值。

1

它有一定的气味的解决方法,但这种方法应该满足您的需求:

private bool _hasInitialized = false; 
private void Form1_Shown(object sender, EventArgs e) 
{  
    if (!_hasInitialized) 
    { 
     ThreadPool.QueueUserWorkItem(state => 
     { 
      Thread.Sleep(200); // brief sleep to allow the main thread 
           // to paint the form nicely 
      this.Invoke((Action)delegate { LoadData(); });  
     }); 
    } 
} 

private void LoadData() 
{ 
    // do the data loading 
    _hasInitialized = true; 
} 

它所做的是,如果它已经被初始化之前它反应显示窗体时,支票和如果没有,它会产生一个线程,它将在主线程上调用LoadData方法之前等待一小段时间。这将允许表单正确绘制。该samething或许可以通过简单地调用this.Refresh()来实现,但我喜欢让系统的想法决定如何做的工作。

我还是会尝试将数据加载推到一个工作线程,主线程上调用回用于填充UI(如果它是与COM组件在所有可能的)。

0

是不是FormShown你正在寻找的事件?

+0

但是,UI线程在控件加载时仍会阻塞,导致应用程序无响应,对吧? – 2009-11-11 16:03:23

+0

打算编辑我​​的帖子以获取更多详细信息:)... 是的,Fredrik提出的建议(穿线)。我只是在开始线程之前用Application.DoEvents()替换Thread.Sleep()。 – 2009-11-11 16:06:01

0

当你说你不能使用,因为COM的后台线程你是什么意思?我在我的应用程序中使用了许多COM组件,并在后台线程上运行它们。

如果您创建一个新的线程作为STAThread你也许可以加载在一个非UI线程组合框/列表框。 IIRC ThreadPool将工作线程分配为MTAThread,因此您需要实际手动创建线程而不是使用ThreadPool.QueueUserWorkItem。