Супер медленный пользовательский элемент управления C#

Я сделал пользовательский элемент управления, это FlowLayoutPanel, в который я поместил кучу других пользовательских элементов управления (только кнопки, каждый с тремя метками и наложенным PictureBox)

Он работает нормально примерно с 100 кнопками, но увеличьте его до 1000, и у него проблемы. Увеличьте это до 5000, и он просто умирает через 20 секунд.

У меня очень мало пользовательского кода, и я разумно использую макет приостановки и возобновления.

Так что я делаю не так? Я уверен, что мой (довольно быстрый) компьютер должен обрабатывать несколько тысяч кнопок и ярлыков.

(Я довольно новичок в C# GUI, так что, возможно, мне все равно придется делать все по-другому.)

Изменить 1:

На данный момент это практически единственный пользовательский код:

flowLayoutPanel1.SuspendLayout();
foreach (DataRow row in dt.Rows) // dt is from a DB query
{
    flowLayoutPanel1.Controls.Add(new PersonButton(row));
}
flowLayoutPanel1.ResumeLayout();

и в конструкторе PersonButton:

this.label1.Text = row["FirstName"].ToString().Trim() + " "
    + row["Surname"].ToString().Trim();

(Там также должна быть прикреплена картинка, но я не уверен, что кто-нибудь ее увидит.)

Изменить 2:

Думаю, мне действительно следует использовать DataGridView или ListView, но я хотел больше, чем просто строка текста и маленький значок в строке; Я хотел, чтобы он выглядел аналогично представлению загрузок в Firefox (Ctrl + J). (Смотрите скриншот)

Большое спасибо за ваш вклад, кстати. Я думаю, мне придется переосмыслить...

http://img156.imageshack.us/img156/1057/capture.png

7 ответов

Решение

Может ли приложение C# WinForm обрабатывать 1000 экземпляров любого типа элемента управления? Я не гуру WinForm, но то, что вы ожидаете от своего приложения, может быть необоснованным.

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

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

Кроме того, ваш лучший выбор #1 для профилирования вашего кода. Профилирование - это единственный верный способ узнать, что именно медленно работает в вашем коде. По моему опыту, это особенно верно для кода пользовательского интерфейса.

[Некромантический режим = ВКЛ]

У вас есть 1000 строк данных, но вы можете показать только некоторые из них, поэтому создайте только те элементы управления, которые будут видны, и используйте их повторно, меняя их содержимое с новыми данными при прокрутке.

Логика расположения, требуемая для элементов управления 5k, будет слишком большой для любого типа оберточной панели. Возможно, вы захотите взглянуть на другой тип элемента управления, разработанного для хранения тысяч записей - что-то вроде DataGridView.

В DataGridView доступно несколько различных типов столбцов, которые должны работать с типом отображаемых данных (изображения, кнопки, метки). Поскольку ваш запрос к базе данных, похоже, возвращает DataTable, вы можете просто привязать его непосредственно к DataGridView и удалить цикл.

Похоже, вы серьезно должны переосмыслить свой интерфейс.

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

Однако я провел некоторые эксперименты, рассматривая время для создания новых элементов управления в коде, даже используя отражение, и обнаружил, что несколько сотен элементов управления с привязкой к данным, созданных на лету в панели макета потока, должны быть созданы за 1-2 секунды.

Размещение большего количества примеров кода может помочь получить лучший ответ.

Больше информации: я только что снова запустил свой тест синхронизации, 300 контролей заняли 0,5 секунды, 400 - 1,9 секунды, 600 - 3 секунды, 1000 - 6 секунд.
Кажется, что где-то между 300 и 400 существует предел, когда ресурсы начинают перерасходоваться.

При более чем 1000 кнопках у вас, вероятно, слишком мало ресурсов GDI и / или необработанных дескрипторов для вашего приложения.

Не уверен, что ваше приложение должно делать, но сетка или поле со списком может быть лучшим вариантом здесь.

Попробуй это; поместите этот метод в ваш код.

защищенное переопределение CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= 0x02000000; вернуть cp; } }

Другие вопросы по тегам