Winforms: SuspendLayout/ResumeLayout недостаточно?

Хотя нет воспроизводимого примера, который бы помог в вашей конкретной ситуации, рассмотрите возможность выполнения запросов чистого SQL UPDATE с привязанными параметрами. Ваша условная логика для области может быть переписана во вложенное выражение IIF. Возможно, это упростит вашу проблему и оптимизирует ваши потребности без DLookup или нескольких обновлений набора записей. Кроме того, переназначение RowSource не требуется. Ниже используется параметризация, которая рекомендуется при запуске SQL на уровне приложений:

SQL (сохраните оба ниже как запросы Access)

  1. mySavedJoinUpdateQuery

    PARAMETERS Text33Param Text(255), Text35Param Text(255)
               Text37Param Text(255), JobNumberParam Text(255);
    UPDATE [To_Do] d
    INNER JOIN [Job Route] r
    ON d.Job_Number = r.Job_Number
    
    SET [Area] = IIF([Current] = 1 AND [Area2] != '---', [Area2], 
                     IIF([Current] = 2 AND [Area3] != '---', [Area3], 
                         IIF([Current] = 3 AND [Area4] != '---', [Area4], [Area1)
                     )
                 ),
        [Person_In_Charge] = Text33Param,
        [Equipment] = Text37Param,
        [Description] = Text35Param
    
    WHERE r.[Job Number] = JobNumberParam;
    
  2. mySavedSimpleUpdateQuery

    PARAMETERS JobNumberParam Text(255);
    UPDATE [Job Route] r
    SET r.[Current] = r.[Current] + 1
    WHERE r.[Job Number] = JobNumberParam;
    

VBA

Private Sub moveJob2_Click()
   Dim qdef As QueryDef
   Dim selectParas As String

   ' UPDATE JOIN QUERY
   Set qdef = CurrentDb.QueryDefs("mySavedJoinUpdateQuery")

   qdef!JobNumberParam = Text31
   qdef!Text33Param = Text33
   qdef!Text35Param = Text35
   qdef!Text37Param = Text37

   qdef.Execute dbFailOnError 
   Set qdef = Nothing

   ' UPDATE SIMPLE QUERY
   Set qdef = CurrentDb.QueryDefs("mySavedSimpleUpdateQuery")

   qdef!JobNumberParam = Text31   
   qdef.Execute dbFailOnError 
   Set qdef = Nothing

   ' REQUERY LIST BOXES
   listRemoveJobs.Requery
   listChangeJobArea.Requery
End Sub
26
задан Martin Marconcini 7 May 2009 в 14:47
поделиться

9 ответов

В дополнение к свойству DoubleBuffered также попробуйте добавить это в конструктор вашего элемента управления:

SetStyle(ControlStyles.OptimizedDoubleBuffer | 
         ControlStyles.AllPaintingInWmPaint, true);

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

4
ответ дан 28 November 2019 в 07:22
поделиться

Мы тоже видели эту проблему.

Один из способов, который мы видели, чтобы «исправить» это, - это полностью приостановить рисование элемента управления, пока мы не будем готовы к работе. Для этого мы отправляем элементу управления сообщение WM_SETREDRAW:

// Note that WM_SetRedraw = 0XB

// Suspend drawing.
UnsafeSharedNativeMethods.SendMessage(handle, WindowMessages.WM_SETREDRAW, IntPtr.Zero, IntPtr.Zero);

...

// Resume drawing.
UnsafeSharedNativeMethods.SendMessage(handle, WindowMessages.WM_SETREDRAW, new IntPtr(1), IntPtr.Zero);
12
ответ дан 28 November 2019 в 07:22
поделиться

Я подойду к вашей проблеме с точки зрения производительности.

цикл foreach, который будет создавать метки, добавить их на панель (с двойной буферизацией) и изменить их свойства

Если все сделано в таком порядке, есть место для улучшения. Сначала создайте все свои ярлыки, измените их свойства и, когда все они будут готовы, добавьте их на панель: Panel.Controls.AddRange (Control [])

В большинстве случаев все, что мы делаем, это рисуем закругленные углы и добавить градиент на задний план

Вы делаете одно и то же снова и снова? Как создаются ваши градиенты? Написание изображения не может быть таким медленным. Однажды мне пришлось создать градиент 1680x1050 в памяти, и это было очень быстро, вроде бы слишком быстро для секундомера , поэтому рисовать градиент не так сложно.

Я бы посоветовал: попробуйте кэшировать кое-что. Откройте Paint, нарисуйте углы и сохраните их на диск или создайте изображение в памяти только один раз. Затем загрузите (и измените размер) по мере необходимости. То же самое для градиента.

Даже если разные кнопки имеют разные цвета, но один и тот же мотив, вы можете создать растровое изображение с помощью Paint или чего-то еще и во время выполнения загрузить его и умножить значения Color на другой Color.

EDIT:

, если приостановить раскладку панели перед цикл и возобновление макета панели по окончании цикла

SuspendLayout и ResumeLayout предназначены не для этого. Они приостанавливают логику компоновки, то есть автоматическое позиционирование элементов управления. Наиболее актуально для FlowLayoutPanel и TableLayoutPanel.

Что касается двойной буферизации, я не уверен, что она применима к пользовательскому коду отрисовки (не пробовал). Думаю, вам стоит реализовать свое собственное.

В двух словах о двойном буфере: Это очень просто, пара строк кода. В событии рисования выполните рендеринг в растровое изображение вместо рендеринга в объект Graphics , а затем нарисуйте это растровое изображение в объект Graphics .

9
ответ дан 28 November 2019 в 07:22
поделиться

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

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

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

Надеюсь, это поможет.

11
ответ дан 28 November 2019 в 07:22
поделиться

У меня было много подобных проблем в прошлом, и я решил их использовать сторонний набор пользовательских интерфейсов (то есть DevExpress ) а не стандартные элементы управления Microsoft.

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

Я перешел на DevExpress и могу сказать только хорошее. Продукт надежный, они обеспечивают отличную поддержку и документацию, и да, они действительно прислушиваются к своим клиентам. Каждый раз, когда у меня возникал вопрос или проблема, я получал дружеский ответ в течение 24 часов. В нескольких случаях

0
ответ дан 28 November 2019 в 07:22
поделиться

Может быть, сначала нарисуйте "видимый" (частный) буфер, предназначенный только для элементов управления, а затем отрендерите его:

В вашем элементе управления

BufferedGraphicsContext gfxManager;
BufferedGraphics gfxBuffer;
Graphics gfx;

Функция для установки графики

private void InstallGFX(bool forceInstall)
{
    if (forceInstall || gfxManager == null)
    {
        gfxManager = BufferedGraphicsManager.Current;
        gfxBuffer = gfxManager.Allocate(this.CreateGraphics(), new Rectangle(0, 0, Width, Height));
        gfx = gfxBuffer.Graphics;
    }
}

В ее отрисовке метод

protected override void OnPaint(PaintEventArgs e)
{
    InstallGFX(false);
    // .. use GFX to draw
    gfxBuffer.Render(e.Graphics);
}

В его методе изменения размера

protected override void OnSizeChanged(EventArgs e)
{
    base.OnSizeChanged(e);
    InstallGFX(true); // To reallocate drawing space of new size
}

Приведенный выше код был несколько протестирован.

2
ответ дан 28 November 2019 в 07:22
поделиться

Похоже, то, что вы ищете, является "составным" дисплеем, где все приложение отображается одновременно, почти как одно большое растровое изображение. Это то, что происходит с приложениями WPF, за исключением «хрома», окружающего приложение (такие вещи, как строка заголовка, ручки изменения размера и полосы прокрутки).

Обратите внимание, что обычно, если вы не испортили некоторые стили окна, каждый элемент управления Windows Form отвечает за само рисование. То есть каждый элемент управления получает трещину при рисовании связанных сообщений WM_ PAINT, WM_ NCPAINT, WM_ERASEBKGND и т. Д. И обрабатывает эти сообщения независимо. Для вас это означает, что двойная буферизация применяется только к единственному элементу управления, с которым вы имеете дело. Чтобы приблизиться к чистому составному эффекту, вам нужно позаботиться не только о ваших настраиваемых элементах управления, которые вы рисуете, но и о контейнерных элементах управления, на которых они размещаются. Например, если у вас есть форма, содержащая GroupBox, который, в свою очередь, содержит ряд настраиваемых нарисованных кнопок, каждый из этих элементов управления должен иметь свойство DoubleBuffered, установленное на True. Обратите внимание, что это свойство защищено, так что это означает, что вы либо в конечном итоге наследуете различные элементы управления (просто для установки свойства двойной буферизации), либо используете отражение для установки защищенного свойства. Кроме того, не все элементы управления Windows Form учитывают свойство DoubleBuffered, так как внутри некоторые из них являются просто оболочками вокруг «общих» элементов управления.

Существует способ установить составной флаг, если вы ориентируетесь на Windows XP (и, предположительно, более позднюю версию). ). Есть стиль окна WS_ EX_ COMPOSITED. Я использовал его раньше, чтобы смешивать результаты. Он плохо работает с гибридными приложениями WPF / WinForm, а также плохо работает с элементом управления DataGridView. Если вы пойдете по этому пути, обязательно проведите много тестов на разных машинах, потому что я видел странные результаты. В конце концов, я отказался от использования этого подхода.

поскольку внутренне некоторые из них являются просто оболочками вокруг «общих» элементов управления.

Существует способ установить составной флаг, если вы ориентируетесь на Windows XP (и, предположительно, более позднюю версию). Есть стиль окна WS_ EX_ COMPOSITED. Я использовал его раньше, чтобы смешивать результаты. Он плохо работает с гибридными приложениями WPF / WinForm, а также плохо работает с элементом управления DataGridView. Если вы пойдете по этому пути, обязательно проведите много тестов на разных машинах, потому что я видел странные результаты. В конце концов, я отказался от использования этого подхода.

поскольку внутренне некоторые из них являются просто оболочками вокруг «общих» элементов управления.

Существует способ установить составной флаг, если вы ориентируетесь на Windows XP (и, предположительно, более позднюю версию). Есть стиль окна WS_ EX_ COMPOSITED. Я использовал его раньше, чтобы смешивать результаты. Он плохо работает с гибридными приложениями WPF / WinForm, а также плохо работает с элементом управления DataGridView. Если вы пойдете по этому пути, обязательно проведите много тестов на разных машинах, потому что я видел странные результаты. В конце концов, я отказался от использования этого подхода.

t хорошо работает с гибридными приложениями WPF / WinForm, а также плохо работает с элементом управления DataGridView. Если вы пойдете по этому пути, обязательно проведите много тестов на разных машинах, потому что я видел странные результаты. В конце концов, я отказался от использования этого подхода.

t хорошо работает с гибридными приложениями WPF / WinForm, а также плохо работает с элементом управления DataGridView. Если вы пойдете по этому пути, обязательно проведите много тестов на разных машинах, потому что я видел странные результаты. В конце концов, я отказался от использования этого подхода.

2
ответ дан 28 November 2019 в 07:22
поделиться

Вы можете посмотреть ответ на мой вопрос: Как мне приостановить рисование для элемента управления и его дочерних элементов? для лучшего приостановления / возобновления.

2
ответ дан 28 November 2019 в 07:22
поделиться

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

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

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace myNameSpace.Forms.UserControls
{
    public class TableLayoutPanelNoFlicker : TableLayoutPanel
    {
        public TableLayoutPanelNoFlicker()
        {
            this.DoubleBuffered = true;
        }
    }
}
0
ответ дан 28 November 2019 в 07:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: