Pertanyaan Kinerja redraw yang mengerikan dari DataGridView di salah satu dari dua layar saya


Saya sebenarnya sudah memecahkan ini, tapi saya mempostingnya untuk anak cucu.

Saya mengalami masalah yang sangat aneh dengan DataGridView pada sistem dual-monitor saya. Masalah memanifestasikan dirinya sebagai pengekangan yang sangat EXTREMELY lambat dari kontrol (seperti 30 detik untuk pengecatan ulang penuh), tetapi hanya ketika ada di salah satu layar saya. Ketika di sisi lain, kecepatan repainting baik-baik saja.

Saya memiliki Nvidia 8800 GT dengan driver non-beta terbaru (175. sesuatu). Apakah ini bug driver? Saya akan meninggalkannya di udara, karena saya harus hidup dengan konfigurasi khusus ini. (Itu tidak terjadi pada kartu ATI, meskipun ...)

Kecepatan cat tidak ada hubungannya dengan isi sel, dan gambar kustom tidak meningkatkan kinerja sama sekali - bahkan ketika hanya menggambar persegi panjang yang solid.

Saya kemudian mengetahui bahwa menempatkan ElementHost (dari System.Windows.Forms.Integration namespace) pada formulir mengoreksi masalah. Itu tidak harus dikacaukan; itu hanya perlu menjadi anak dari bentuk DataGridView juga aktif. Ini dapat diubah ukurannya ke (0, 0) selama Terlihat properti itu benar.

Saya tidak ingin secara eksplisit menambahkan ketergantungan .NET 3 / 3.5 ke aplikasi saya; Saya membuat metode untuk membuat kontrol ini saat runtime (jika bisa) menggunakan refleksi. Ini bekerja, dan setidaknya gagal dengan anggun pada mesin yang tidak memiliki perpustakaan yang dibutuhkan - itu hanya kembali menjadi lambat.

Metode ini juga memungkinkan saya menerapkan untuk memperbaiki saat aplikasi sedang berjalan, membuatnya lebih mudah untuk melihat apa yang diubah oleh perpustakaan WPF pada formulir saya (menggunakan Spy ++).

Setelah banyak trial and error, saya melihat bahwa memungkinkan buffering ganda pada kontrol itu sendiri (bukan hanya bentuk) memperbaiki masalah!


Jadi, Anda hanya perlu membuat kelas khusus berdasarkan dari DataGridView sehingga Anda dapat mengaktifkan DoubleBuffering-nya. Itu dia!

class CustomDataGridView: DataGridView
{
    public CustomDataGridView()
    {
        DoubleBuffered = true;
    }
}

Selama semua contoh saya menggunakan versi kustom ini, semuanya baik-baik saja. Jika saya mengalami situasi yang disebabkan oleh ini di mana saya tidak dapat menggunakan solusi subclass (jika saya tidak memiliki kode), saya kira saya bisa mencoba untuk menyuntikkan kontrol itu ke dalam bentuk :) (meskipun saya akan lebih cenderung mencoba menggunakan refleksi untuk memaksa properti DoubleBuffered dari luar untuk sekali lagi menghindari ketergantungan).

Sangat menyedihkan bahwa hal sepele seperti itu menghabiskan begitu banyak waktu saya ...


76
2017-09-23 01:01


asal


Jawaban:


Anda hanya perlu membuat kelas khusus berdasarkan dari DataGridView sehingga Anda dapat mengaktifkan DoubleBuffering-nya. Itu dia!


class CustomDataGridView: DataGridView
{
    public CustomDataGridView()
    {
        DoubleBuffered = true;
    } 
}

Selama semua contoh saya menggunakan versi kustom ini, semuanya baik-baik saja. Jika saya mengalami situasi yang disebabkan oleh ini di mana saya tidak dapat menggunakan solusi subclass (jika saya tidak memiliki kode), saya kira saya bisa mencoba untuk menyuntikkan kontrol itu ke form :) (meskipun saya Akan lebih mungkin untuk mencoba menggunakan refleksi untuk memaksa properti DoubleBuffered dari luar untuk sekali lagi menghindari ketergantungan).

Sangat menyedihkan bahwa hal sepele seperti itu menghabiskan begitu banyak waktu saya ...

Catatan: Menjawab jawabannya sehingga pertanyaannya dapat ditandai sebagai dijawab


60
2017-10-01 19:49



Berikut adalah beberapa kode yang mengatur properti menggunakan refleksi, tanpa subclass seperti yang dikatakan Benoit.

typeof(DataGridView).InvokeMember(
   "DoubleBuffered", 
   BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty,
   null, 
   myDataGridViewObject, 
   new object[] { true });

57
2018-04-24 18:52



Bagi orang yang mencari cara melakukannya di VB.NET, berikut adalah kodenya:

DataGridView1.GetType.InvokeMember("DoubleBuffered", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance Or System.Reflection.BindingFlags.SetProperty, Nothing, DataGridView1, New Object() {True})

13
2018-04-13 16:45



Jawaban untuk ini juga berhasil untuk saya. Saya pikir saya akan menambahkan penyempurnaan yang saya pikir harus menjadi praktik standar bagi siapa pun yang menerapkan solusi.

Solusinya berfungsi dengan baik kecuali ketika UI sedang dijalankan sebagai sesi klien di bawah remote desktop, terutama di mana bandwidth jaringan yang tersedia rendah. Dalam kasus seperti itu, kinerja dapat diperburuk oleh penggunaan buffer ganda. Oleh karena itu, saya sarankan yang berikut sebagai jawaban yang lebih lengkap:

class CustomDataGridView: DataGridView
{
    public CustomDataGridView()
    {
        // if not remote desktop session then enable double-buffering optimization
        if (!System.Windows.Forms.SystemInformation.TerminalServerSession)
            DoubleBuffered = true;
    } 
}

Untuk lebih jelasnya, lihat Mendeteksi koneksi remote desktop


6
2018-05-18 15:15



Menambah posting sebelumnya, untuk aplikasi Windows Forms inilah yang saya gunakan untuk komponen-komponen DataGridView untuk membuatnya cepat. Kode untuk kelas DrawingControl ada di bawah.

DrawingControl.SetDoubleBuffered(control)
DrawingControl.SuspendDrawing(control)
DrawingControl.ResumeDrawing(control)

Panggil DrawingControl.SetDoubleBuffered (kontrol) setelah InitializeComponent () di konstruktor.

Panggil DrawingControl.SuspendDrawing (kontrol) sebelum melakukan pembaruan data besar.

Call DrawingControl.ResumeDrawing (kontrol) setelah melakukan pembaruan data besar.

2 terakhir ini paling baik dilakukan dengan blok try / finally. (atau menulis ulang kelas dengan lebih baik sebagai IDisposable dan telepon SuspendDrawing() dalam konstruktor dan ResumeDrawing() di 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();
    }
}

6
2017-10-07 20:28



Saya menemukan solusi untuk masalah ini. Buka tab troubleshoot di properti tampilan lanjutan dan periksa penggeser akselerasi perangkat keras. Ketika saya mendapatkan PC perusahaan baru saya dari IT, itu diatur menjadi satu tik dari penuh dan saya tidak memiliki masalah dengan datagrid. Setelah saya memperbarui driver kartu video dan mengaturnya penuh, lukisan kontrol datagrid menjadi sangat lambat. Jadi saya mengatur ulang kembali ke tempatnya dan masalahnya hilang.

Semoga trik ini bekerja untuk Anda juga.


1
2018-02-26 22:35



Hanya untuk menambahkan apa yang kami lakukan untuk memperbaiki masalah ini: Kami meng-upgrade ke driver Nvidia terbaru memecahkan masalah. Tidak ada kode yang harus ditulis ulang.

Untuk kelengkapan, kartu itu adalah Nvidia Quadro NVS 290 dengan driver tanggal Maret 2008 (v. 169). Upgrade ke yang terbaru (v. 182 bertanggal Februari 2009) secara signifikan meningkatkan acara melukis untuk semua kontrol saya, terutama untuk DataGridView.

Masalah ini tidak terlihat pada kartu ATI (di mana pengembangan terjadi).


1
2018-06-10 16:54