Хотя нет воспроизводимого примера, который бы помог в вашей конкретной ситуации, рассмотрите возможность выполнения запросов чистого SQL UPDATE
с привязанными параметрами. Ваша условная логика для области может быть переписана во вложенное выражение IIF
. Возможно, это упростит вашу проблему и оптимизирует ваши потребности без DLookup
или нескольких обновлений набора записей. Кроме того, переназначение RowSource
не требуется. Ниже используется параметризация, которая рекомендуется при запуске SQL на уровне приложений:
SQL (сохраните оба ниже как запросы Access)
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;
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
В дополнение к свойству DoubleBuffered
также попробуйте добавить это в конструктор вашего элемента управления:
SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint, true);
И если этого окажется недостаточно (что я собираюсь пойти на конечности и скажите, что это не так), посмотрите на мой ответ на на этот вопрос и приостановите / возобновите перерисовку панели или формы. Это позволит завершить операции макета, а затем выполнить весь рисунок, как только это будет сделано.
Мы тоже видели эту проблему.
Один из способов, который мы видели, чтобы «исправить» это, - это полностью приостановить рисование элемента управления, пока мы не будем готовы к работе. Для этого мы отправляем элементу управления сообщение 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);
Я подойду к вашей проблеме с точки зрения производительности.
цикл foreach, который будет создавать метки, добавить их на панель (с двойной буферизацией) и изменить их свойства
Если все сделано в таком порядке, есть место для улучшения. Сначала создайте все свои ярлыки, измените их свойства и, когда все они будут готовы, добавьте их на панель: Panel.Controls.AddRange (Control [])
В большинстве случаев все, что мы делаем, это рисуем закругленные углы и добавить градиент на задний план
Вы делаете одно и то же снова и снова? Как создаются ваши градиенты? Написание изображения не может быть таким медленным. Однажды мне пришлось создать градиент 1680x1050 в памяти, и это было очень быстро, вроде бы слишком быстро для секундомера
, поэтому рисовать градиент не так сложно.
Я бы посоветовал: попробуйте кэшировать кое-что. Откройте Paint, нарисуйте углы и сохраните их на диск или создайте изображение в памяти только один раз. Затем загрузите (и измените размер) по мере необходимости. То же самое для градиента.
Даже если разные кнопки имеют разные цвета, но один и тот же мотив, вы можете создать растровое изображение с помощью Paint или чего-то еще и во время выполнения загрузить его и умножить значения Color на другой Color.
EDIT:
, если приостановить раскладку панели перед цикл и возобновление макета панели по окончании цикла
SuspendLayout и ResumeLayout предназначены не для этого. Они приостанавливают логику компоновки, то есть автоматическое позиционирование элементов управления. Наиболее актуально для FlowLayoutPanel и TableLayoutPanel.
Что касается двойной буферизации, я не уверен, что она применима к пользовательскому коду отрисовки (не пробовал). Думаю, вам стоит реализовать свое собственное.
В двух словах о двойном буфере:
Это очень просто, пара строк кода. В событии рисования выполните рендеринг в растровое изображение вместо рендеринга в объект Graphics
, а затем нарисуйте это растровое изображение в объект Graphics
.
Одна из вещей, на которую вы должны обратить внимание, - это установили ли вы BackColor = Transparent для любого из дочерних элементов управления ваших панелей. BackColor = Transparent значительно ухудшит производительность рендеринга, особенно если родительские панели используют градиенты.
Windows Forms не использует настоящую прозрачность, а использует «фальшивую». Каждый вызов рисования дочернего элемента управления генерирует вызов рисования для родительского элемента, чтобы родитель мог рисовать свой фон, поверх которого дочерний элемент управления рисует свое содержимое, чтобы оно выглядело прозрачным.
Итак, если у вас есть 50 дочерних элементов управления, которые будут генерировать дополнительные 50 вызовов рисования в родительском элементе управления для фоновая живопись. А поскольку градиенты обычно медленнее, вы увидите снижение производительности.
Надеюсь, это поможет.
У меня было много подобных проблем в прошлом, и я решил их использовать сторонний набор пользовательских интерфейсов (то есть DevExpress ) а не стандартные элементы управления Microsoft.
Я начал использовать стандартные элементы управления Microsoft, но обнаружил, что постоянно отлаживаю проблемы, вызванные их элементами управления. Проблема усугубляется тем фактом, что Microsoft обычно не исправляет ни одной из выявленных проблем и очень мало делает для обеспечения подходящих обходных путей.
Я перешел на DevExpress и могу сказать только хорошее. Продукт надежный, они обеспечивают отличную поддержку и документацию, и да, они действительно прислушиваются к своим клиентам. Каждый раз, когда у меня возникал вопрос или проблема, я получал дружеский ответ в течение 24 часов. В нескольких случаях
Может быть, сначала нарисуйте "видимый" (частный) буфер, предназначенный только для элементов управления, а затем отрендерите его:
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
}
Приведенный выше код был несколько протестирован.
Похоже, то, что вы ищете, является "составным" дисплеем, где все приложение отображается одновременно, почти как одно большое растровое изображение. Это то, что происходит с приложениями 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. Если вы пойдете по этому пути, обязательно проведите много тестов на разных машинах, потому что я видел странные результаты. В конце концов, я отказался от использования этого подхода.Вы можете посмотреть ответ на мой вопрос: Как мне приостановить рисование для элемента управления и его дочерних элементов? для лучшего приостановления / возобновления.
У меня была такая же проблема с 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;
}
}
}