Я действительно решил эту проблему, но отправляю ее для потомков.
Я столкнулся с очень странной проблемой с DataGridView в моей системе с двумя мониторами. Проблема проявляется как ЧРЕЗВЫЧАЙНО медленная перерисовка элемента управления ( например, 30 секунд для полной перерисовки ), но только когда он находится на одном из моих экранов. Когда с другой, скорость перекраски в порядке.
У меня есть Nvidia 8800 GT с последними не бета-драйверами (175 с лишним). Это ошибка драйвера? Я оставлю это в воздухе, так как я должен жить с этой конкретной конфигурацией. (Хотя на картах ATI этого не происходит ...)
Скорость рисования не имеет ничего общего с содержимым ячеек, а пользовательское рисование вообще не улучшает производительность - даже при рисовании сплошного прямоугольника.
Позже я обнаружил, что размещение ElementHost (из пространства имен System.Windows.Forms.Integration) в форме решает проблему. С этим не нужно связываться; он просто должен быть дочерним по отношению к форме, в которой также находится DataGridView. Его размер можно изменить до (0, 0), пока свойство Visible имеет значение true.
Я не хочу явно добавлять в свое приложение зависимость .NET 3 / 3.5; Я создаю метод для создания этого элемента управления во время выполнения (если это возможно) с использованием отражения. Он работает, и, по крайней мере, он корректно выходит из строя на машинах, на которых нет необходимой библиотеки - он просто снова становится медленным.
Этот метод также позволяет мне применять исправления во время работы приложения, что упрощает просмотр изменений в библиотеках WPF в моей форме (с помощью Spy ++).
После множества проб и ошибок я заметил, что включение двойной буферизации для самого элемента управления (а не только для формы) решает проблему!
Итак, вам просто нужно создать собственный класс на основе DataGridView, чтобы вы могли включить его DoubleBuffering. Это оно!
class CustomDataGridView: DataGridView
{
public CustomDataGridView()
{
DoubleBuffered = true;
}
}
Пока все мои экземпляры сетки используют эту настраиваемую версию, все в порядке. Если я когда-нибудь столкнусь с ситуацией, вызванной этим, когда я не смогу использовать решение подкласса (если у меня нет кода), я полагаю, я мог бы попытаться ввести этот элемент управления в форму :) ( хотя я ' с большей вероятностью я попытаюсь использовать отражение для принудительного включения свойства DoubleBuffered извне, чтобы снова избежать зависимости ).
Печально, что такая банально простая вещь отнимала у меня столько времени ...
источник
Ответы:
Вам просто нужно создать собственный класс на основе DataGridView, чтобы вы могли включить его DoubleBuffering. Это оно!
class CustomDataGridView: DataGridView { public CustomDataGridView() { DoubleBuffered = true; } }
Пока все мои экземпляры сетки используют эту настраиваемую версию, все в порядке. Если я когда-нибудь столкнусь с ситуацией, вызванной этим, когда я не смогу использовать решение подкласса (если у меня нет кода), я полагаю, я мог бы попытаться ввести этот элемент управления в форму :) (хотя я ' с большей вероятностью я попытаюсь использовать отражение для принудительного включения свойства DoubleBuffered извне, чтобы снова избежать зависимости).
Печально, что такая банально простая вещь отнимала у меня столько времени ...
Примечание. Сделайте ответ как ответ, чтобы вопрос можно было пометить как ответ.
источник
Вот код, который устанавливает свойство с помощью отражения, без создания подклассов, как предлагает Бенуа.
typeof(DataGridView).InvokeMember( "DoubleBuffered", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, myDataGridViewObject, new object[] { true });
источник
Control
класса.public static void ToggleDoubleBuffered(this Control control, bool isDoubleBuffered)
.Для людей, которые ищут, как это сделать в VB.NET, вот код:
DataGridView1.GetType.InvokeMember("DoubleBuffered", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance Or System.Reflection.BindingFlags.SetProperty, Nothing, DataGridView1, New Object() {True})
источник
Добавляя к предыдущим сообщениям, для приложений Windows Forms это то, что я использую для компонентов DataGridView, чтобы сделать их быстрыми. Код для класса DrawingControl приведен ниже.
DrawingControl.SetDoubleBuffered(control) DrawingControl.SuspendDrawing(control) DrawingControl.ResumeDrawing(control)
Вызовите DrawingControl.SetDoubleBuffered (control) после InitializeComponent () в конструкторе.
Вызовите DrawingControl.SuspendDrawing (элемент управления) перед выполнением больших обновлений данных.
Вызовите DrawingControl.ResumeDrawing (control) после выполнения больших обновлений данных.
Эти последние 2 лучше всего выполнять с помощью блока try / finally. (а еще лучше переписать класс как
IDisposable
и вызватьSuspendDrawing()
в конструкторе иResumeDrawing()
вDispose()
.)using System.Runtime.InteropServices; public static class DrawingControl { [DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam); private const int WM_SETREDRAW = 11; /// <summary> /// Some controls, such as the DataGridView, do not allow setting the DoubleBuffered property. /// It is set as a protected property. This method is a work-around to allow setting it. /// Call this in the constructor just after InitializeComponent(). /// </summary> /// <param name="control">The Control on which to set DoubleBuffered to true.</param> public static void SetDoubleBuffered(Control control) { // if not remote desktop session then enable double-buffering optimization if (!System.Windows.Forms.SystemInformation.TerminalServerSession) { // set instance non-public property with name "DoubleBuffered" to true typeof(Control).InvokeMember("DoubleBuffered", System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic, null, control, new object[] { true }); } } /// <summary> /// Suspend drawing updates for the specified control. After the control has been updated /// call DrawingControl.ResumeDrawing(Control control). /// </summary> /// <param name="control">The control to suspend draw updates on.</param> public static void SuspendDrawing(Control control) { SendMessage(control.Handle, WM_SETREDRAW, false, 0); } /// <summary> /// Resume drawing updates for the specified control. /// </summary> /// <param name="control">The control to resume draw updates on.</param> public static void ResumeDrawing(Control control) { SendMessage(control.Handle, WM_SETREDRAW, true, 0); control.Refresh(); } }
источник
Ответ на этот вопрос сработал и для меня. Я подумал, что добавлю уточнение, которое, на мой взгляд, должно стать стандартной практикой для всех, кто внедряет решение.
Решение работает хорошо, за исключением случаев, когда пользовательский интерфейс запускается в качестве клиентского сеанса на удаленном рабочем столе, особенно когда доступная пропускная способность сети низкая. В таком случае производительность может быть снижена за счет использования двойной буферизации. Поэтому в качестве более полного ответа предлагаю следующее:
class CustomDataGridView: DataGridView { public CustomDataGridView() { // if not remote desktop session then enable double-buffering optimization if (!System.Windows.Forms.SystemInformation.TerminalServerSession) DoubleBuffered = true; } }
Дополнительные сведения см. В разделе «Обнаружение подключения к удаленному рабочему столу».
источник
Нашел решение проблемы. Перейдите на вкладку устранения неполадок в расширенных свойствах дисплея и проверьте ползунок аппаратного ускорения. Когда я получил от ИТ-отдела свой новый корпоративный компьютер, он был установлен на одну отметку от полной, и у меня не было никаких проблем с сетями данных. Как только я обновил драйвер видеокарты и установил его на полную, отрисовка элементов управления сеткой данных стала очень медленной. Поэтому я вернул его на место, и проблема исчезла.
Надеюсь, этот трюк сработает и для вас.
источник
Просто чтобы добавить, что мы сделали для решения этой проблемы: мы обновили драйверы Nvidia до последней версии, и проблема была решена. Переписывать код не пришлось.
Для полноты картины это была карта Nvidia Quadro NVS 290 с драйверами от марта 2008 г. (v. 169). Обновление до последней версии (версия 182 от февраля 2009 г.) значительно улучшило события рисования для всех моих элементов управления, особенно для DataGridView.
Эта проблема не наблюдалась ни на каких картах ATI (где идет разработка).
источник
Лучший!:
Private Declare Function SendMessage Lib "user32" _ Alias "SendMessageA" _ (ByVal hWnd As Integer, ByVal wMsg As Integer, _ ByVal wParam As Integer, ByRef lParam As Object) _ As Integer Const WM_SETREDRAW As Integer = &HB Public Sub SuspendControl(this As Control) SendMessage(this.Handle, WM_SETREDRAW, 0, 0) End Sub Public Sub ResumeControl(this As Control) RedrawControl(this, True) End Sub Public Sub RedrawControl(this As Control, refresh As Boolean) SendMessage(this.Handle, WM_SETREDRAW, 1, 0) If refresh Then this.Refresh() End If End Sub
источник
Мы столкнулись с аналогичной проблемой при использовании .NET 3.0 и DataGridView в системе с двумя мониторами.
Наше приложение будет отображать сетку на сером фоне, указывая на то, что ячейки нельзя изменить. После выбора кнопки «изменить настройки» программа изменит цвет фона ячеек на белый, чтобы указать пользователю, что текст ячейки может быть изменен. Кнопка «отменить» изменит цвет фона вышеупомянутых ячеек обратно на серый.
При изменении цвета фона будет мерцание, краткое впечатление от сетки размера по умолчанию с тем же количеством строк и столбцов. Эта проблема может возникнуть только на основном мониторе (но не на дополнительном) и не может возникнуть в системе с одним монитором.
Двойная буферизация элемента управления на примере выше решила нашу проблему. Мы очень ценим вашу помощь.
источник