Frage

Ich habe das eigentlich gelöst, aber ich bin Entsendung es für die Nachwelt.

Ich lief in ein sehr seltsames Problem mit dem Datagridview auf meinem Dual-Monitor-System. Das Problem manifestiert sich als eine extrem langsame Repaint der Kontrolle ( wie 30 Sekunden für eine volle repaint ), aber nur, wenn es auf einem meiner Bildschirme ist. Wenn auf der anderen Seite der Neuzeichnungsindex Geschwindigkeit ist in Ordnung.

Ich habe eine Nvidia 8800 GT mit dem neuesten Nicht-Beta-Treiber (175. etwas). Ist es ein Treiber-Problem? Ich werde das in der Luft überlassen, da ich mit dieser besonderen Konfiguration leben. (Es geschieht nicht auf ATI-Karten, obwohl ...)

Die Farbe Geschwindigkeit hat nichts mit den Zellinhalt zu tun, und benutzerdefinierte Zeichnen Sie die Leistung überhaupt nicht verbessert -., Selbst wenn nur ein festes Rechteck Malerei

ich später herausfinden, dass ein Element platzieren (aus dem System.Windows.Forms.Integration Namespace) auf dem Formular das Problem behebt. Es muss nicht spaßen; es muss nur die Datagridview auch auf ein Kind der Form sein. Es kann zu der Größe verändert werden (0, 0), solange die Visible Eigenschaft gilt.

Ich will nicht explizit die .NET-3 / 3.5 Abhängigkeit meiner Anwendung hinzuzufügen; Ich mache eine Methode, um diese Kontrolle zur Laufzeit zu erstellen (wenn das möglich ist) mit Reflexion. Es funktioniert, und es zumindest nicht ordnungsgemäß auf Maschinen, die die erforderliche Bibliothek nicht haben -. Es geht einfach wieder langsam zu sein

Auch diese Methode kann mich anwenden zu beheben, während die App ausgeführt werden, ist es leichter zu sehen, zu machen, was die WPF-Bibliotheken auf meiner Form ändern (mit Spy ++).

Nach einer Menge von Versuch und Irrtum, ich merke, dass sich auf der Steuer Double-Buffering ermöglicht (im Gegensatz zu nur die Form) wird das Problem gelöst!


Also, Sie müssen nur eine benutzerdefinierte Klasse machen basierte weg von Datagridview, so dass Sie sein Doublebuffering aktivieren. Das ist es!

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

Solange alle meine Instanzen des Gitters dieses kundenspezifische Version verwenden, ist alles gut. Wenn ich jemals in eine Situation, die dadurch verursacht laufen, wo ich nicht in der Lage bin, die Unterklasse-Lösung zu verwenden (wenn ich den Code nicht habe), ich glaube, ich könnte versuchen, diese Kontrolle auf die Form zu injizieren :) ( obwohl ich eher versuchen, mithilfe von Reflektion auf die Eigenschaft DoubleBuffered zu zwingen, von außen, um erneut die Abhängigkeit vermeiden ).

Es ist traurig, dass ein solcher trivialer einfache Sache viel von meiner Zeit so aß ...

War es hilfreich?

Lösung

Sie müssen nur eine benutzerdefinierte Klasse machen aus der Datagridview-basiert, so dass Sie seine Doublebuffering aktivieren. Das ist es!


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

Solange alle meine Instanzen des Gitters dieses kundenspezifische Version verwenden, ist alles gut. Wenn ich jemals in eine Situation, die dadurch verursacht laufen, wo ich nicht in der Lage bin, die Unterklasse-Lösung zu verwenden (wenn ich den Code nicht habe), nehme ich mich versuchen könnte, dass die Kontrolle auf die Form zu injizieren :) (obwohl ich ll eher von außen versuchen, mithilfe von Reflektion auf die Eigenschaft DoubleBuffered zwingen, noch einmal, um die Abhängigkeit) zu vermeiden.

Es ist traurig, dass ein solcher trivialer einfache Sache viel von meiner Zeit so aß ...

Hinweis: Erstellen Sie die Antwort eine Antwort so die Frage beantwortet markiert werden können

Andere Tipps

Hier ist ein Code, der die Eigenschaft mithilfe von Reflektion, ohne Subclassing setzt als Benoit schlägt.

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

Für Menschen auf der Suche, wie es in VB.NET zu tun, hier ist der Code:

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

Hinzufügen zum vorherigen Beiträgen, für Windows Forms-Anwendungen ist das, was ich für Datagridview-Komponenten verwenden, um sie schnell zu machen. Der Code für die Klasse drawingControl ist unten.

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

Rufen DrawingControl.SetDoubleBuffered (Kontrolle) nach InitializeComponent () im Konstruktor.

Rufen DrawingControl.SuspendDrawing (Kontrolle) vor großen Daten-Updates zu tun.

Rufen DrawingControl.ResumeDrawing (Kontrolle) nach großen Daten-Updates zu tun.

Diese letzten 2 werden am besten mit einem Versuch gemacht / finally-Block. (Oder noch besser umschreiben die Klasse als IDisposable und Call SuspendDrawing() im Konstruktor und ResumeDrawing() in 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();
    }
}

Die Antwort auf diese arbeitete auch für mich. Ich dachte, ich würde eine Verfeinerung hinzufügen, dass ich denke, sollte gängige Praxis für alle, die Implementierung der Lösung.

Die Lösung funktioniert gut, außer wenn der UI als Client-Sitzung unter Remote-Desktop ausgeführt wird, insbesondere dann, wenn die verfügbare Netzwerkbandbreite gering ist. In einem solchen Fall kann die Leistung schlechter durch die Verwendung von Double-Buffering gemacht werden. Daher schlage ich die folgenden als vollständigere Antwort:

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

Weitere Informationen finden Sie unter Remote-Desktop-Verbindung Erkennung

fand ich eine Lösung für das Problem. Gehen Sie Registerkarte in den erweiterten Anzeigeeigenschaften zu beheben und prüfen Sie den Schieberegler Hardwarebeschleunigung. Als ich von der IT meinen neuen Firma PC bekam, wurde es von voll auf einen Tick gesetzt und ich habe keine Probleme mit Datagrids. Sobald ich den Grafikkartentreiber aktualisiert und den vollen gesetzt wurde Malerei von Datagrid Kontrollen sehr langsam. So setze ich es zurück, wo es war, und das Problem ging weg.

Hope dieser Trick auch für Sie arbeitet.

Just fügen, was wir dieses Problem zu beheben haben: Wir bekamen ein Upgrade auf den neuesten Nvidia-Treiber das Problem gelöst. hatte kein Code neu geschrieben werden.

Für die Vollständigkeit, war die Karte eine Nvidia Quadro NVS 290 mit Treibern März 2008 datiert (v. 169). Ein Upgrade auf die neueste (v. 182 vom Februar 2009) deutlich die Farbe Ereignisse verbessert für alle meine Kontrollen, vor allem für die Datagridview.

Dieses Problem nicht auf all ATI-Karten zu sehen war (wo die Entwicklung stattfindet).

Best:

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

Wir haben ein ähnliches Problem .NET 3.0 und Datagridview auf einem Dual-Monitor-System erfahren werden.

Unsere Anwendung würde das Gitter mit einem grauen Hintergrund angezeigt, was darauf hinweist, dass die Zellen nicht verändert werden können. Bei der Auswahl einer „Einstellungen ändern“ klicken, würde das Programm der Hintergrund ändern Farbe der Zellen wissen, um den Benutzer anzuzeigen, dass die Zelle Text geändert werden. Eine Schaltfläche „Abbrechen“ würde die Hintergrundfarbe der oben genannten Zellen verändern zurück zu grau.

Da die Hintergrundfarbe dort veränderte ein Flimmern wäre, ein kurzer Eindruck eines Standard-Größe Gitter mit der gleichen Anzahl von Zeilen und Spalten. Dieses Problem würde nur auf dem primären Monitor auftritt (nie die sekundären) und es wäre nicht auf einem einzigen Monitor System auftreten.

Doppelte Pufferung der Steuerung, das obige Beispiel verwendet wird, gelöst unser Problem. Wir schätzten Ihre Hilfe.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top