There were already a few similar questions on stackoverflow, but I haven't found the answer
I have an application that consists of several tab pages. On one of them I'm loading a list of a few dozen user controls at a time. Currently I'm doing it in Load event and because of that I have a small delay before this page is loaded. What I want to do is to make UI more responsive and fill the list after the page is fully loaded. Is there any way to track when the user control has fully loaded it's content?
VisibleChanged doesn't help too, because it fires before any other child control is shown. That causes some ugly visual effects wh开发者_Python百科en some of the child controls are still not visible when I'm starting to load control list.
EDIT
To make it more clear. I have some child controls on a page container and I have a list of custom controls I'm trying to load later. The problem with two approaches described in several answers below is that when I'm starting to load controls they do not let other child controls on the container to be shown and that is why I have those ugly effects (and I'm doing that with BackgroundWorker, but anyway it has to interact with the main thread to add controls to the list)
In order to make the UI more responsive, you should post yourself a message (Control.BeginInvoke
), do one operation, post yourself another message. Then every time you do anything, the next step will get queued after all user messages, so user actions will get processed promptly.
One really nifty approach is to use yield return
and let the compiler take care of all the closures logic:
IEnumerable AsyncLoadUI()
{
var p = new Panel();
Controls.Add(p);
yield return null;
for( int i = 0; i < 50; ++i ) {
var txt = new TextBox();
p.Controls.Add(txt);
yield return null;
}
}
override void OnLoad(EventArgs e)
{
IEnumerator tasks = AsyncLoadUI().GetEnumerator();
MethodInvoker msg = null;
msg = delegate { if (tasks.MoveNext()) BeginInvoke(msg); };
msg();
}
Take a look at my solution offered to another. They had a very similar issue. Wait until EVERYTHING finished its loading before doing a certain action, but not every time a form necessarily became "activated" or "shown". It involves attaching to the Load handler of your outermost control of interest. In your case, the tabbed page, but the example solution I provided was at the FORM level.
If the loading of this list incurs a small delay then doing this load on the UI thread will always make the form unresponsive no matter what event you do it in - changing this to be done after the form has loaded then it will just make the form unresponsive and visible as opposed to just causing a delay before the form is shown.
If there is no way to speed up the loading of the list then you will probably need to change your form loading logic so that the "heavy lifting" is instead done in a background thread so that the form remains responsive while the list is being populated. You should be aware that multithreaded code is more difficult to understand and when done incorrectly can produce bugs that are intermittant and difficult to debug and so you should definitely try to speed up your existing code first. That said if you can't speed up your list loading and the delay is unacceptable then there is not really any alternative.
If you do choose to load your list asynchronously (in a background thread) then the idea is to start a background thread (usually via a BackgroundWorker ) that does the hard work of preparing a list of items to be added - when this has finished (or failed) the form / list box is updated with the supplied list of items.
You should be able to find plenty of resources on how to do this on the internet that will cover this in more detail.
精彩评论