मेरे दो स्क्रीन में से एक पर DataGridView का भयानक redraw प्रदर्शन


81

मैंने वास्तव में इसे हल कर लिया है, लेकिन मैं इसे पोस्टीरिटी के लिए पोस्ट कर रहा हूं।

मैं अपने दोहरे मॉनिटर सिस्टम पर DataGridView के साथ एक बहुत ही अजीब मुद्दे में भाग गया। समस्या अपने आप में नियंत्रण के एक धीमी गति से पुनरावृत्ति के रूप में प्रकट होती है ( जैसे पूर्ण प्रतिनिधि के लिए 30 सेकंड ), लेकिन केवल जब यह मेरी एक स्क्रीन पर है। जब दूसरे पर, दमन गति ठीक है।

मेरे पास नवीनतम गैर-बीटा ड्राइवरों (175. कुछ) के साथ एनवीडिया 8800 जीटी है। क्या यह ड्राइवर बग है? मैं इसे हवा में छोड़ दूंगा, क्योंकि मुझे इस विशेष विन्यास के साथ रहना है। (यह अति कार्ड पर नहीं होता है, हालांकि ...)

रंग की गति का सेल सामग्री के साथ कोई लेना-देना नहीं है, और कस्टम ड्राइंग प्रदर्शन को बेहतर नहीं करता है - यहां तक ​​कि जब सिर्फ एक ठोस आयत पेंटिंग।

मुझे बाद में पता चला कि फॉर्म पर एक ElementHost (System.Windows.Forms.Integration namespace) रखने से समस्या ठीक हो जाती है। इसके साथ खिलवाड़ नहीं करना है; यह सिर्फ उस प्रपत्र का एक बच्चा होने की आवश्यकता है जिस पर DataGridView भी चालू है। इसे (0, 0) के रूप में देखा जा सकता है, जब तक दृश्यमान गुण सत्य है।

मैं अपने आवेदन में .NET 3 / 3.5 निर्भरता को स्पष्ट रूप से जोड़ना नहीं चाहता; मैं रनटाइम पर इस नियंत्रण को बनाने के लिए एक विधि बनाता हूं (यदि यह हो सकता है) प्रतिबिंब का उपयोग कर। यह काम करता है, और कम से कम यह उन मशीनों पर इनायत से विफल हो जाता है जिनके पास आवश्यक पुस्तकालय नहीं है - यह बस धीमा होने के लिए वापस जाता है।

यह विधि मुझे एप को चलाने के दौरान ठीक करने के लिए आवेदन करने की सुविधा भी देती है, जिससे यह देखना आसान हो जाता है कि WPF लाइब्रेरी मेरे फॉर्म में क्या बदल रही है (स्पाई ++ का उपयोग करके)।

बहुत परीक्षण और त्रुटि के बाद, मैंने नोटिस किया कि नियंत्रण पर डबल बफ़रिंग को सक्षम करना (केवल फॉर्म के विपरीत) समस्या को ठीक करता है!


इसलिए, आपको केवल डेटाग्रिडव्यू के आधार पर एक कस्टम क्लास बनाने की आवश्यकता है ताकि आप इसके डबलबेरिंग को सक्षम कर सकें। बस!

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

जब तक ग्रिड के मेरे सभी उदाहरण इस कस्टम संस्करण का उपयोग कर रहे हैं, तब तक सब ठीक है। अगर मैं कभी इस वजह से किसी स्थिति में भाग जाता हूं, जहां मैं उपवर्ग समाधान (यदि मेरे पास कोड नहीं है) का उपयोग करने में सक्षम नहीं है, तो मुझे लगता है कि मैं उस नियंत्रण को फॉर्म पर इंजेक्ट करने की कोशिश कर सकता हूं :) ( हालांकि मैं ' एक बार फिर से निर्भरता से बचने के लिए डबलबर्फर की गई संपत्ति को बाहर से लाने के लिए प्रतिबिंब का उपयोग करने की कोशिश करने की अधिक संभावना होगी

यह दुखद है कि इतनी मामूली सी बात मेरे समय का इतना खा गई ...


1
हमारे पास उन ग्राहकों के साथ एक समान मुद्दा था जिन्होंने मल्टीमोन स्थापित किया है। जो भी कारण से, जब वे मल्टीमोन को बंद कर देते हैं, तो समस्या दूर हो जाती है।
ब्लूराजा - डैनी Pflughoeft

किसी को भी पता है और समझा सकता है कि ऐसा क्यों होता है और डिफ़ॉल्ट रूप से DoubleBuffered को चालू क्यों नहीं किया जा सकता है?
वोजत दोहल

जवाबों:


64

आपको बस डेटाग्रिडव्यू के आधार पर एक कस्टम क्लास बनाने की आवश्यकता है ताकि आप इसके डबलबेरिंग को सक्षम कर सकें। बस!


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

जब तक ग्रिड के मेरे सभी उदाहरण इस कस्टम संस्करण का उपयोग कर रहे हैं, तब तक सब ठीक है। अगर मैं कभी इस वजह से किसी स्थिति में भाग जाता हूं, जहां मैं उपवर्ग समाधान (यदि मेरे पास कोड नहीं है) का उपयोग करने में सक्षम नहीं है, तो मुझे लगता है कि मैं उस नियंत्रण को फॉर्म पर इंजेक्ट करने की कोशिश कर सकता हूं :) (हालांकि मैं ' एक बार फिर से निर्भरता से बचने के लिए डबलबर्फर की गई संपत्ति को बाहर से लाने के लिए प्रतिबिंब का उपयोग करने की कोशिश करने की अधिक संभावना होगी।

यह दुखद है कि इतनी मामूली सी बात मेरे समय का इतना खा गई ...

नोट: उत्तर को उत्तर देना ताकि प्रश्न को उत्तर के रूप में चिह्नित किया जा सके


1
आप WPF के लिए विंडोज फॉर्म इंटीग्रेशन के साथ यह कैसे कर सकते हैं ??
आंशिक

जवाब के लिए धन्यवाद। आप कभी-कभी उपवर्ग समाधान का उपयोग कैसे नहीं कर पाएंगे? (मुझे समझ नहीं आया "यदि मेरे पास कोड नहीं है")।
दान डब्ल्यू।

बहुत खुबस! मेरी परियोजना में एक आकर्षण की तरह काम करता है जो टेबल पर आबादी और स्क्रॉलिंग दोनों में अजीब मंदी से पीड़ित था (:
19'15

61

यहाँ कुछ कोड है जो बेनोइट के सुझाव के बिना, उप-वर्ग के बिना, प्रतिबिंब का उपयोग करके संपत्ति सेट करता है।

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

3
मदद करने में खुशी! मैंने इसे लगभग पोस्ट नहीं किया क्योंकि यह प्रश्न पहले से ही एक वर्ष पुराना था।
ब्रायन सुनिश्चित

1
हाँ, यह हमेशा भविष्य में किसी की मदद करेगा, जैसे कि शायद मैं भी, जिसने अभी-अभी यह धागा Google से पाया है। धन्यवाद! Btw, क्या यह Form1_Load अनुभाग में रखना बेहतर है?
डैन डब्ल्यू

2
बस किसी और को देने के लिए जो इसे एक विचार देता है: यह Controlकक्षा पर एक उपयोगी विस्तार विधि है । public static void ToggleDoubleBuffered(this Control control, bool isDoubleBuffered)
एंथोनी

क्या इसे एफओआरएम के लोड इवेंट पर रखा जा सकता है जहां डेटा ग्रिड दृश्य रखा गया है?
अरी

18

VB.NET में इसे करने के तरीके की खोज करने वाले लोगों के लिए, यहाँ कोड है:

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

10

पिछली पोस्टों में जोड़कर, विंडोज फॉर्म के अनुप्रयोगों के लिए यह वही है जो मैं डेटाग्रिडव्यू घटकों के लिए उन्हें तेज बनाने के लिए उपयोग करता हूं। वर्ग DrawingControl के लिए कोड नीचे है।

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

निर्माता में InitializeComponent () के बाद DrawingControl.SetDoubleBuffered (नियंत्रण) को कॉल करें।

बड़ा डेटा अपडेट करने से पहले DrawingControl.SuspendDrawing (नियंत्रण) पर कॉल करें।

बड़ा डेटा अपडेट करने के बाद DrawingControl.ResumeDrawing (नियंत्रण) पर कॉल करें।

ये अंतिम 2 एक कोशिश / अंत में ब्लॉक के साथ सबसे अच्छा किया जाता है। (या बेहतर तरीके से कक्षा को फिर से लिखना 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();
    }
}

7

इस के जवाब ने मेरे लिए भी काम किया। मैंने सोचा कि मैं एक शोधन जोड़ दूंगा जो मुझे लगता है कि समाधान को लागू करने वाले किसी भी व्यक्ति के लिए मानक अभ्यास होना चाहिए।

यूआई दूरस्थ डेस्कटॉप के तहत क्लाइंट सत्र के रूप में चलाया जा रहा है, विशेष रूप से जहां उपलब्ध नेटवर्क बैंडविड्थ कम है, को छोड़कर समाधान अच्छा काम करता है। ऐसे मामले में, डबल-बफरिंग के उपयोग से प्रदर्शन को और खराब किया जा सकता है। इसलिए, मैं निम्नलिखित और अधिक पूर्ण उत्तर के रूप में सुझाव देता हूं:

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

अधिक जानकारी के लिए, दूरस्थ डेस्कटॉप कनेक्शन का पता लगाने का संदर्भ लें


1

मुझे समस्या का हल मिल गया। उन्नत प्रदर्शन गुणों में समस्या निवारण टैब पर जाएं और हार्डवेयर त्वरण स्लाइडर की जांच करें। जब मुझे आईटी से मेरी नई कंपनी पीसी मिली, तो यह पूर्ण से एक टिक पर सेट थी और मुझे डेटाग्रिड्स के साथ कोई समस्या नहीं थी। एक बार जब मैंने वीडियो कार्ड ड्राइवर को अपडेट किया और इसे पूरा सेट किया, तो डेटाग्रिड नियंत्रण की पेंटिंग बहुत धीमी हो गई। इसलिए मैंने इसे वापस उसी स्थान पर रीसेट कर दिया जहां यह था और समस्या दूर हो गई।

आशा है कि यह ट्रिक आपके लिए भी काम करे।


1

इस समस्या को हल करने के लिए हमने जो कुछ किया है, उसे जोड़ने के लिए: हमने नवीनतम एनवीडिया ड्राइवरों को अपग्रेड किया जिससे समस्या हल हुई। किसी भी कोड को फिर से लिखना नहीं पड़ा।

पूर्णता के लिए, कार्ड मार्च 2008 (v। 169) के ड्राइवरों के साथ एनवीडिया क्वाड्रो एनवीएस 290 था। नवीनतम (v। 182 दिनांकित फरवरी 2009) में अपग्रेड करने से मेरे सभी नियंत्रणों के लिए विशेष रूप से DataGridView के लिए पेंट ईवेंट में काफी सुधार हुआ।

यह समस्या किसी भी एटीआई कार्ड (जहां विकास होता है) पर नहीं देखी गई थी।


1

श्रेष्ठ!:

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

0

हमने .NET मॉनिटर और दोहरी मॉनिटर सिस्टम पर DataGridView का उपयोग करके एक समान समस्या का अनुभव किया है।

हमारा एप्लिकेशन ग्रिड को एक ग्रे बैकग्राउंड के साथ प्रदर्शित करेगा, यह दर्शाता है कि कोशिकाओं को बदला नहीं जा सकता है। एक "परिवर्तन सेटिंग्स" बटन का चयन करने पर, प्रोग्राम उपयोगकर्ता को इंगित करने के लिए कोशिकाओं के सफेद रंग की पृष्ठभूमि का रंग बदल देगा कि सेल पाठ को बदला जा सकता है। एक "रद्द करें" बटन पूर्वोन्मुखी कोशिकाओं की पृष्ठभूमि का रंग बदलकर ग्रे कर देगा।

जैसा कि पृष्ठभूमि का रंग बदल गया है एक झिलमिलाहट होगी, पंक्तियों और स्तंभों की समान संख्या के साथ एक डिफ़ॉल्ट आकार के ग्रिड का एक संक्षिप्त प्रभाव। यह समस्या केवल प्राथमिक मॉनीटर (कभी भी द्वितीयक) पर नहीं होगी और यह एकल मॉनीटर सिस्टम पर नहीं होगी।

नियंत्रण को दोगुना करने के लिए, उपरोक्त उदाहरण का उपयोग करके, हमारी समस्या को हल किया। हमने आपकी मदद की बहुत सराहना की।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.