Подтвердить что ты не робот

Windows Forms: использование BackgroundImage замедляет рисование элементов управления Form

У меня есть форма Windows (С#.NET 3.5) с несколькими кнопками и другими элементами управления, которые назначены самой верхней панели, которая охватывает всю форму. Например, иерархия: Form → Panel → другие элементы управления.

Как только я назначаю BackgroundImage для панели, элементы управления рисуют очень медленно. У меня такой же эффект, если я использую свойство Form BackgroundImage и устанавливаю Panel BackgroundColor на "прозрачный". Кажется, что сначала создается окно с фоном, затем каждый элемент управления добавляется один за другим с небольшой задержкой до следующего рисования. Другими словами, вы можете фактически следовать порядку, в котором каждый элемент управления обращается к форме. После того, как все элементы управления будут нарисованы, как только этот эффект больше не произойдет, но отзывчивость формы все еще медленная.

В дизайнере Visual Studio я получаю тот же эффект, особенно заметно при перемещении элементов управления. Иногда чертеж формы полностью останавливается на секунду или два, что делает работу с BackgroundImage полным перетаскиванием как в дизайнере, так и в результате приложения.

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

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

private void LoadControls(Form form)
{
    this.SuspendLayout();

    this.DoubleBuffered = true;
    EnableDoubleBuffering(this.Controls);

    this.BackgroundImage = form.BackgroundImage;
    this.BackColor = form.BackColor;

    this.Controls.Clear();
    foreach (Control c in form.Controls)
    {
        this.Controls.Add(c);
    }

    this.ResumeLayout();
}

Как вы можете видеть, SuspendLayout() и ResumeLayout() используются, чтобы избежать ненужного перерисовки.

Тем не менее, форма "медленно, как ад", когда используется BackgroundImage. Я даже попытался преобразовать его в PNG, JPG и BMP, чтобы понять, не имеет значения. Кроме того, изображение имеет размер 1024x768, но меньшие изображения имеют тот же эффект замедления (хотя и немного меньше).

Что мне делать?

4b9b3361

Ответ 1

SuspendLayout() и ResumeLayout() не приостанавливать рисование, а только операции с макетом. Дайте этому парню выстрел:

public static class ControlHelper
{
    #region Redraw Suspend/Resume
    [DllImport("user32.dll", EntryPoint = "SendMessageA", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
    private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
    private const int WM_SETREDRAW = 0xB;

    public static void SuspendDrawing(this Control target)
    {
        SendMessage(target.Handle, WM_SETREDRAW, 0, 0);
    }

    public static void ResumeDrawing(this Control target) { ResumeDrawing(target, true); }
    public static void ResumeDrawing(this Control target, bool redraw)
    {
        SendMessage(target.Handle, WM_SETREDRAW, 1, 0);

        if (redraw)
        {
            target.Refresh();
        }
    }
    #endregion
}

Использование должно быть довольно понятным, а синтаксис идентичен SuspendLayout() и ResumeLayout(). Это методы расширения, которые будут отображаться в любом экземпляре элемента управления.

Ответ 2

Я также столкнулся с той же проблемой и смог ее решить, уменьшив разрешение фонового изображения. Когда вы используете в качестве фона большие изображения размера (например: 1280X800), потребуется время рисовать элементы управления в форме. Лучше открыть картинку в размере "Макет", размер которой меньше вашей формы, а затем сохранить в формате "bmp". Теперь попробуйте добавить это изображение в качестве фона вашей формы.

Ответ 3

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

panelParent.visible = false;

for(...) {
    // Add your controls here:
    panelParent.Controls.Add(...);
}

panelParent.visible = true;

Ответ 4

Для меня сообщение Загрузка формы медленно при добавлении фонового изображения разрешила проблему:

Удостоверьтесь, что для фона не установлено значение "прозрачно". Для повышения производительности установите его "белый".

Кроме того, BackgroundImageLayout быть либо "Центром", либо " Stretch 'для повышения производительности. Это позволит использовать двойной буфер в форме.

Ответ 5

Я понимаю, что это старый поток, но я нашел его при поиске информации по той же проблеме, поэтому в случае, если это кому-то полезно в какой-то момент:

Моя ситуация: у меня есть сетка размером 13 x 12, которая динамически настраивается фоновым изображением и регулярно изменяется на основе пользовательских настроек. Каждая панель также имеет элемент управления текстовыми метками. Для того, чтобы текст накладывал фоновое изображение, он должен быть установлен на Transparent (btw - мой опыт состоял в том, что BackgroundImageLayout из Zoom, Stretch, Center практически не имел никакого эффекта. BackColor, установленный на прозрачный или белый, также имел небольшой эффект).

Каждая нить сетки панелей (включая изменение размера) занимала около секунды - неплохо, но очень заметно, и проблема юзабилити на более медленных машинах.

Мои изображения не были огромными, но несколько негабаритными.

Что я нашел: изменив размер моего набора изображений на точный размер панели перед настройкой backgroundimage, время рисования резко сократилось - где-то около 0,1 секунды. Поскольку моя программа динамически изменяет размеры панелей на основе размера окна, я динамически изменяю размер набора изображений один раз при изменении размера окна перед установкой фона из 156 панелей.

Оглядываясь назад, его очевидная оптимизация... изменяет размер 8 изображений один раз, а не раз 156 раз.

Ответ 6

Я решил такую ​​же проблему, используя PictureBox. Просто добавьте PictureBox в свой контейнер, выберите "Док-станция в родительском контейнере" (или свойство Dock= Fill) и установите для него изображение. Он будет выглядеть так же, как BackGroundImage родительского элемента управления.