Как я могу установить защищенное свойство DoubleBuffered для элементов управления в форме, которые страдают от мерцания?





public void EnableDoubleBuffering()
{
this.SetStyle(ControlStyles.DoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint,
true);
this.UpdateStyles();
}
System.Reflection.PropertyInfo aProp = typeof(System.Windows.Forms.Control)
.GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
aProp.SetValue(ListView1, true, null);
Ян содержит дополнительную информацию об использовании этого на сервере терминалов.
Это не совсем для на как терминального сервера, поскольку ни один из моих клиентов не запускает программное обеспечение из сеанса удаленного рабочего стола. Но вы должны платить налоги разработчикам, а я не хотел выпускать код, который еще не включал налоги.
Вы также можете унаследовать элементы управления от своих классов и установить там свойство. Этот метод также удобен, если вы склонны выполнять множество настроек, одинаковых для всех элементов управления.
Один из способов - расширить конкретный элемент управления, который вы хотите удвоить, и установить свойство DoubleBuffered внутри ctor элемента управления.
Например:
class Foo : Panel
{
public Foo() { DoubleBuffered = true; }
}
Я работаю с владельцем, нарисованным ListView в производном классе. Это отлично решило проблему!
Не знаю, есть ли недостатки, но это сработало отлично. Мой настраиваемый элемент управления ранее унаследован от «Control», и я просто изменил его, чтобы вместо этого унаследовать от «Panel», и установил для DoubleBuffered значение true. Смена двух строк. Движение плавное ... и скорость рисования одного обновления тоже кажется намного выше.
Прежде чем попробовать двойную буферизацию, посмотрите, решит ли SuspendLayout () / ResumeLayout () вашу проблему.
Suspend / ResumeLayout не решает проблему мерцания при рисовании.
Вот более общая версия Решение пустышки.
Мы можем использовать отражение, чтобы получить защищенное свойство DoubleBuffered, а затем его можно установить на истинный.
Примечание: вам следует платить налоги застройщикам, а не используйте двойную буферизацию, если пользователь работает в сеансе терминальных служб (например, удаленный рабочий стол). Этот вспомогательный метод не будет включать двойную буферизацию, если пользователь работает на удаленном рабочем столе.
public static void SetDoubleBuffered(System.Windows.Forms.Control c)
{
//Taxes: Remote Desktop Connection and painting
//http://blogs.msdn.com/oldnewthing/archive/2006/01/03/508694.aspx
if (System.Windows.Forms.SystemInformation.TerminalServerSession)
return;
System.Reflection.PropertyInfo aProp =
typeof(System.Windows.Forms.Control).GetProperty(
"DoubleBuffered",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
aProp.SetValue(c, true, null);
}
Забавно, я думаю, что еще важнее использовать двойную буферизацию при удаленном взаимодействии, чтобы избежать ненужной отправки кучи перерисовок по сети?
Это именно то, чего вы не хотите. В терминальном сеансе система GDI может отправлять команды (нарисовать линию здесь, нарисовать круг здесь, заполнить здесь и т. д.). Двойная буферизация достигается за счет того, что вы рисуете все на растровом изображении, а затем используете GDI для рисования всей вашей формы как растрового изображения. Отправка несжатого растрового изображения по сети на МНОГО медленнее, чем отправка исходных команд GDI.
Не помогает предотвратить мерцание TextBox с автоматическим размером при изменении размера ... На самом деле ничего из того, что я пробовал до сих пор, не помогает.
@Boris Это потому, что Windows TEXTBOX контролирует законы рисования не подчиняется никакому.
@romkyns, Если вам нужен TextBox с двойной буферизацией, используйте RichTextBox с DetectUrls, установленным на False. Если вы хотите, чтобы его можно было редактировать, удалите форматирование с помощью сообщений EM_SETCHARFORMAT и EM_SETPARAFORMAT (пример кода это здесь).
@IanBoyd Я знаю, что это очень старый вопрос, но подумал, что все равно попробую. У меня была такая же проблема с моим приложением, поэтому я преобразовал приведенный выше код в VB.NET и добавил его в свой основной класс формы. Затем я добавил SetDoubleBuffered(SplashScreen) непосредственно перед SplashScreen.Show() в свой DisplaySplashSub. Оно работает! Однако я совершенно новичок в подобных вещах, и я не уверен, правильный ли это способ реализовать это?
Я обнаружил, что простая установка параметра DoubleBuffered в форме автоматически устанавливает все свойства, перечисленные здесь.
да, я знаю ... Я потерял этот код и не смог найти его нигде в Интернете ... извините!
Проверить эта ветка
Повторяя суть этого ответа, вы можете включить флаг стиля WS_EX_COMPOSITED в окне, чтобы получить как форму, так и все ее элементы управления с двойной буферизацией. Флаг стиля доступен с XP. Это не ускоряет рисование, но все окно отрисовывается во внеэкранном буфере и переносится на экран одним движением. Мгновенный вид для глаз пользователя без видимых артефактов рисования. Это не совсем без проблем, некоторые средства визуализации визуальных стилей могут давать сбои, особенно TabControl, когда у него слишком много вкладок. YMMV.
Вставьте этот код в свой класс формы:
protected override CreateParams CreateParams {
get {
var cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED
return cp;
}
}
Большая разница между этой техникой и поддержкой двойной буферизации Winform заключается в том, что версия Winform работает только с одним элементом управления за раз. Вы по-прежнему будете видеть каждую отдельную контрольную краску. Что также может выглядеть как эффект мерцания, особенно если неокрашенный прямоугольник элемента управления плохо контрастирует с фоном окна.
Однако это решение замедляет прокрутку.
Это решение вызывает проблемы с элементами управления WPF, размещенными внутри ElementHost. Элемент управления не будет правильно нарисован.
Если у вас есть форма с контейнером-разделителем, НЕ используйте WS_EX_COMPOSITED!
Ты мой герой. Спасибо
nobugz получает признание за метод в своей ссылке, я просто репостю. Добавьте это переопределение в форму:
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
Это сработало лучше всего для меня, в Windows 7 у меня появлялись большие черные блоки, когда я изменял размер тяжелой формы элемента управления. Вместо этого элемент управления теперь подпрыгивает! Но так лучше.
Это то же самое, что и ответ @Hans Passant, но +1 за размещение кода здесь.
Способ расширения, чтобы включить или выключить двойную буферизацию для элементов управления
public static class ControlExtentions
{
/// <summary>
/// Turn on or off control double buffering (Dirty hack!)
/// </summary>
/// <param name = "control">Control to operate</param>
/// <param name = "setting">true to turn on double buffering</param>
public static void MakeDoubleBuffered(this Control control, bool setting)
{
Type controlType = control.GetType();
PropertyInfo pi = controlType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
pi.SetValue(control, setting, null);
}
}
Использование (например, как сделать DataGridView DoubleBuffered):
DataGridView _grid = new DataGridView();
// ...
_grid.MakeDoubleBuffered(true);
Это вызвало у меня много горя в течение двух дней со сторонним контролем, пока я не отследил его.
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
Недавно у меня было много дыр (помет) при изменении размера / перерисовке элемента управления, содержащего несколько других элементов управления.
Я пробовал WS_EX_COMPOSITED и WM_SETREDRAW, но ничего не работало, пока я не использовал это:
private void myPanel_SizeChanged(object sender, EventArgs e)
{
Application.DoEvents();
}
Просто хотел передать это дальше.
vb.net версия этого прекрасного решения ....:
Protected Overrides ReadOnly Property CreateParams() As CreateParams
Get
Dim cp As CreateParams = MyBase.CreateParams
cp.ExStyle = cp.ExStyle Or &H2000000
Return cp
End Get
End Property
применимо ли это для двойной буферизации всех элементов управления только в этом кадре?
хороший....! Но мне интересно, почему он все еще мерцает, когда я пытался сделать видимым форму, которая стала ложной?