Как определить, когда пользовательский элемент управления полностью загружен и показан? - PullRequest
10 голосов
/ 11 июля 2011

Уже было несколько похожих вопросов по stackoverflow, но я не нашел ответа

У меня есть приложение, которое состоит из нескольких вкладок.На одном из них я загружаю список из нескольких десятков пользовательских элементов управления одновременно.В настоящее время я делаю это в событии Load и из-за этого у меня небольшая задержка перед загрузкой этой страницы.Что я хочу сделать, так это сделать интерфейс пользователя более отзывчивым и заполнить список после полной загрузки страницы.Есть ли способ отследить, когда пользовательский элемент управления полностью загрузил его содержимое?

VisibleChanged тоже не помогает, потому что он срабатывает до показа любого другого дочернего элемента управления.Это вызывает некоторые неприятные визуальные эффекты, когда некоторые дочерние элементы управления все еще не видны, когда я начинаю загружать список элементов управления.

РЕДАКТИРОВАТЬ

Чтобы сделать его более четким,У меня есть некоторые дочерние элементы управления в контейнере страницы, и у меня есть список пользовательских элементов управления, которые я пытаюсь загрузить позже.Проблема с двумя подходами, описанными в нескольких ответах ниже, состоит в том, что, когда я начинаю загружать элементы управления, они не позволяют отображать другие дочерние элементы управления на контейнере, и именно поэтому у меня есть эти ужасные эффекты (и я делаю это сBackgroundWorker, но в любом случае он должен взаимодействовать с основным потоком, чтобы добавить элементы управления в список)

Ответы [ 3 ]

6 голосов
/ 11 июля 2011

Чтобы пользовательский интерфейс стал более отзывчивым, вы должны отправить себе сообщение (Control.BeginInvoke), выполнить одну операцию, опубликовать себе другое сообщение. Затем каждый раз, когда вы что-либо делаете, следующий шаг будет ставиться в очередь после всех пользовательских сообщений, поэтому действия пользователя будут обрабатываться быстро.

Один действительно изящный подход - использовать yield return и позволить компилятору позаботиться обо всей логике замыканий:

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();
}
2 голосов
/ 11 июля 2011

Взгляните на мое решение, предложенное другому .У них была очень похожая проблема.Подождите, пока ВСЁ не завершит свою загрузку, прежде чем выполнять определенное действие, но не каждый раз, когда форма обязательно становится «активированной» или «показанной».Это включает в себя присоединение к обработчику Load вашего внешнего элемента управления, представляющего интерес.В вашем случае страница с вкладками, но пример решения, который я предоставил, был на уровне FORM.

1 голос
/ 11 июля 2011

Если загрузка этого списка происходит с небольшой задержкой, то выполнение этой загрузки в потоке пользовательского интерфейса всегда делает форму не отвечающей на запросы независимо от того, в каком событии вы ее выполняете - изменив это на выполнение после формыпосле загрузки он просто сделает форму не отвечающей и видимой, в отличие от простой задержки перед отображением формы.

Если нет способа ускорить загрузку списка, вам, вероятно, потребуетсяизмените логику загрузки формы так, чтобы вместо нее выполнялась «тяжелая работа» в фоновом потоке, чтобы форма оставалась отзывчивой во время заполнения списка.Вы должны знать, что многопоточный код сложнее понять, и при неправильном выполнении может привести к ошибкам, которые являются прерывистыми и трудными для отладки, и поэтому вам, безусловно, следует сначала попытаться ускорить существующий код.Тем не менее, если вы не можете ускорить загрузку списка, а задержка недопустима, альтернативы на самом деле нет.

Если вы решите загрузить свой список асинхронно (в фоновом потоке), то идея заключается в том,запустить фоновый поток (обычно через BackgroundWorker ), который выполняет тяжелую работу по подготовке списка элементов, которые будут добавлены - когда это закончено (или не удалось), поле формы / списка обновляется с помощью предоставленногосписок предметов.

Вы сможете найти множество ресурсов о том, как это сделать, в Интернете, которые более подробно расскажут об этом.

...