문제

실제로 이 문제를 해결했지만 후손을 위해 게시합니다.

듀얼 모니터 시스템의 DataGridView에서 매우 이상한 문제가 발생했습니다.이 문제는 컨트롤(전체 다시 칠하는 데 30초 정도 소요), 하지만 내 화면 중 하나에 있을 때만 해당됩니다.반면에 다시 그리기 속도는 괜찮습니다.

최신 비베타 드라이버(175.0)가 설치된 Nvidia 8800 GT가 있습니다.무엇).드라이버 버그인가요?이 특정 구성을 사용해야 하므로 이에 대해서는 공개하지 않겠습니다.(ATI 카드에서는 발생하지 않지만...)

페인트 속도는 셀 내용과 아무 관련이 없으며 사용자 정의 그리기는 성능을 전혀 향상시키지 않습니다. 심지어 단색 직사각형을 그리는 경우에도 마찬가지입니다.

나중에 양식에 ElementHost(System.Windows.Forms.Integration 네임스페이스의)를 배치하면 문제가 해결된다는 사실을 알게 되었습니다.엉망이 될 필요는 없습니다.DataGridView도 있는 형식의 하위 항목이면 됩니다.(0, 0)으로 크기를 조정할 수 있습니다. 보이는 재산은 사실이다.

내 애플리케이션에 .NET 3/3.5 종속성을 명시적으로 추가하고 싶지 않습니다.리플렉션을 사용하여 런타임에(가능한 경우) 이 컨트롤을 생성하는 방법을 만듭니다.작동하지만 최소한 필수 라이브러리가 없는 시스템에서는 정상적으로 실패합니다. 다시 느려질 뿐입니다.

또한 이 방법을 사용하면 앱이 실행되는 동안 수정을 적용할 수 있으므로 WPF 라이브러리가 내 양식(Spy++ 사용)에서 변경하는 내용을 더 쉽게 확인할 수 있습니다.

많은 시행착오 끝에 (단지 양식이 아닌) 컨트롤 자체에서 이중 버퍼링을 활성화하면 문제가 해결된다는 사실을 알게 되었습니다.


따라서 DoubleBuffering을 활성화하려면 DataGridView를 기반으로 사용자 정의 클래스를 만들어야 합니다.그게 다야!

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

모든 그리드 인스턴스가 이 사용자 정의 버전을 사용하는 한 모든 것이 정상입니다.이로 인해 하위 클래스 솔루션을 사용할 수 없는 상황이 발생하면(코드가 없는 경우) 해당 컨트롤을 양식에 삽입해 볼 수 있을 것 같습니다. :) (하지만 나는 다시 한 번 종속성을 피하기 위해 리플렉션을 사용하여 외부에서 DoubleBuffered 속성을 강제로 적용하려고 시도할 가능성이 더 높습니다.).

이런 사소하고 단순한 일이 내 시간을 너무 많이 잡아먹는 게 안타깝다...

도움이 되었습니까?

해결책

DoubleBuffering을 활성화하려면 DataGridView를 기반으로 사용자 정의 클래스를 만들어야 합니다.그게 다야!


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

모든 그리드 인스턴스가 이 사용자 정의 버전을 사용하는 한 모든 것이 정상입니다.이로 인해 하위 클래스 솔루션을 사용할 수 없는 상황이 발생하면(코드가 없는 경우) 해당 컨트롤을 양식에 삽입해 볼 수 있을 것 같습니다. 다시 한 번 종속성을 피하기 위해 리플렉션을 사용하여 외부에서 DoubleBuffered 속성을 강제로 적용하려고 시도할 가능성이 더 높습니다.

이런 사소하고 단순한 일이 내 시간을 너무 많이 잡아먹는 게 안타깝다...

메모:질문을 답변으로 표시할 수 있도록 답변을 답변으로 만들기

다른 팁

다음은 Benoit이 제안한 대로 서브클래싱하지 않고 리플렉션을 사용하여 속성을 설정하는 일부 코드입니다.

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

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)

생성자에서 InitializeComponent() 후에 DrawingControl.SetDoubleBuffered(control)를 호출합니다.

빅데이터 업데이트를 수행하기 전에 DrawingControl.Suspend드로잉(control)을 호출하세요.

빅데이터 업데이트를 수행한 후 DrawingControl.Resume Drawing(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();
    }
}

이에 대한 대답은 나에게도 효과가 있었습니다.나는 솔루션을 구현하는 모든 사람을 위한 표준 관행이 되어야 한다고 생각하는 개선 사항을 추가하겠다고 생각했습니다.

이 솔루션은 UI가 원격 데스크톱에서 클라이언트 세션으로 실행되는 경우, 특히 사용 가능한 네트워크 대역폭이 낮은 경우를 제외하고는 잘 작동합니다.이러한 경우 이중 버퍼링을 사용하면 성능이 저하될 수 있습니다.따라서 보다 완전한 답변으로 다음을 제안합니다.

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

자세한 내용은 다음을 참조하세요. 원격 데스크톱 연결 감지 중

문제에 대한 해결책을 찾았습니다.고급 디스플레이 속성의 문제 해결 탭으로 이동하여 하드웨어 가속 슬라이더를 확인하세요.IT에서 새 회사 PC를 받았을 때 전체에서 1틱으로 설정되어 있었고 데이터 그리드에 문제가 없었습니다.비디오 카드 드라이버를 업데이트하고 전체 설정으로 설정하면 DataGrid 컨트롤 그리기가 매우 느려졌습니다.그래서 다시 원래 위치로 재설정했더니 문제가 사라졌습니다.

이 트릭이 당신에게도 효과가 있기를 바랍니다.

이 문제를 해결하기 위해 수행한 작업을 추가하면 다음과 같습니다.최신 Nvidia 드라이버로 업그레이드하여 문제를 해결했습니다.코드를 다시 작성할 필요가 없었습니다.

완전성을 기하기 위해 카드는 2008년 3월 드라이버가 포함된 Nvidia Quadro NVS 290이었습니다(v.169).최신 버전으로 업그레이드(v.182(2009년 2월자))은 모든 컨트롤, 특히 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를 사용하여 비슷한 문제를 경험했습니다.

우리 응용 프로그램은 회색 배경의 그리드를 표시하여 셀을 변경할 수 없음을 나타냅니다."설정 변경" 버튼을 선택하면 프로그램은 셀 텍스트가 변경될 수 있음을 사용자에게 나타내기 위해 셀의 배경색을 흰색으로 변경합니다."취소" 버튼을 누르면 앞서 언급한 셀의 배경색이 다시 회색으로 변경됩니다.

배경색이 변경됨에 따라 행과 열 수가 동일한 기본 크기의 격자가 간략하게 표시되는 깜박임이 발생합니다.이 문제는 기본 모니터에서만 발생하며(보조 모니터에서는 발생하지 않음) 단일 모니터 시스템에서는 발생하지 않습니다.

위의 예를 사용하여 컨트롤을 이중 버퍼링하면 문제가 해결되었습니다.귀하의 도움에 진심으로 감사드립니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top