¿Cómo evitar que un UserControl (nee ScrollableControl) llame a ScrollWindow?

La redUserControl (que desciende deScrollableControl) tiene la capacidad de mostrar barras de desplazamiento horizontales y verticales.

a persona que llama puede establecer la visibilidad y el rango de estas barras de desplazamiento horizontales y verticales:

UserControl.AutoScroll = true;
UserControl.AutoScrollMinSize = new Size(1000, 4000); //1000x4000 scroll area

Nota LosUserControl (es decir,ScrollableControl) utiliza el mecanismo estándar de Windows para especificarWS_HSCROLL yWS_VSCROLL estilos de ventana para hacer aparecer las barras de desplazamiento. Es decir: no crean controles de desplazamiento de Windows o .NET separados, posicionándolos en la parte derecha / inferior de la ventana. Windows tiene un mecanismo estándar para mostrar una o ambas barras de desplazamiento.

Si el usuario desplaza el control, elUserControl se envía unWM_HSCROLL oWM_VSCROLL mensaje. En respuesta a estos mensajes, quiero que ScrollableControl invalide el área del cliente, que es lo que sucedería en Win32 nativo:

switch (uMsg) 
{ 
   case WM_VSCROLL:
       ...
       GetScrollInfo(...);
       ...
       SetScrollInfo(...);
       ...

       InvalidateRect(g_hWnd, 
              null, //erase entire client area
              true, //background needs erasing too (trigger WM_ERASEBKGND));
       break;
 }

Necesito que toda el área del cliente sea invalidada. El problema es eseControl de usuari (es decir,ScrollableControl) llamadas elScrollWindow Función API:

protected void SetDisplayRectLocation(int x, int y)
{
    ...
    if ((nXAmount != 0) || ((nYAmount != 0) && base.IsHandleCreated))
    {
        ...
        SafeNativeMethods.ScrollWindowEx(new HandleRef(this, base.Handle), nXAmount, nYAmount, null, ref rectClip, NativeMethods.NullHandleRef, ref prcUpdate, 7);
    }
    ...
}

En lugar de activar un InvalidateRect en todo el rectángulo del cliente, ScrollableControl intenta "salva "el contenido existente en el área del cliente. Por ejemplo, el usuario se desplazaarrib, el contenido actual del cliente se empujaabaj porScrollWindowEx, y luego solo se invalida el área recién descubierta, lo que desencadena unWM_PAINT:

En el diagrama anterior, el área del tablero de ajedrez es el contenido que esinválid y deberá pintarse durante la próxima WM_PAINT.

En mi caso esto no es bueno; la parte superior de mi control contiene un "encabezado" (por ejemplo, encabezados de columna de vista de lista). Desplazar este contenido más abajo es incorrecto:

y causa corrupción visual.

i quiero el ScrollableControl paran utilizarScrollWindowEx, pero en cambio solo invalida toda el área del cliente.

intenté anularOnScroll método protegido:

protected override void OnScroll(ScrollEventArgs se)
{
   base.OnScroll(se);

   this.Invalidate();
}

Pero causa un doble empate.

Nota podría usar el doble buffer para enmascarar el problema, pero esa no es una solución real

double buffering no debe usarse en una sesión remota de escritorio / terminal desperdicia recursos de CPU no es la pregunta que hago

i consideró usar unaControl en lugar deUserControl (es decir, antes deScrollableControl en la cadena de herencia) y agregue manualmente un control HScroll o VScroll .NET, pero eso tampoco es deseable:

Windows ya proporciona un aspecto estándar para la posición de las barras de desplazamiento (no es trivial duplicar)es una gran funcionalidad tener que reproducir desde cero, cuando solo quiero que InvalidateRect más bien que ScrollWindowEx

esde que puedo ver, y publicado, el código interno deScrollableControl Sé que no hay propiedad para deshabilitar el uso deScrollWindow, pero ¿existe alguna propiedad para deshabilitar el uso deScrollWindow?

Actualizar

intenté anular el método ofensivo y usar el reflector para robar todo el código:

protected override void SetDisplayRectLocation(int x, int y)
{
    ...
    Rectangle displayRect = this.displayRect;
    ...
    this.displayRect.X = x;
    this.displayRect.Y = y;
    if ((nXAmount != 0) || ((nYAmount != 0) && base.IsHandleCreated))
    {
        ...
        SafeNativeMethods.ScrollWindowEx(new HandleRef(this, base.Handle), nXAmount, nYAmount, null, ref rectClip, NativeMethods.NullHandleRef, ref prcUpdate, 7);
    }
    ...
}

El problema es ese SetDisplayRectLocation lee y escribe en una variable miembro privada displayRect). A menos que Microsoft cambie C # para permitir que los descendientes accedan a miembros privados: no puedo hacer eso.

Update Two

i me di cuenta de que copiar y pegar la implementación deScrollableControl, arreglando elproblem significa que también tendré que copiar y pegar toda la cadena de herencia hastaUserControl

...
   ScrollableControl2 : Control, IArrangedElement, IComponent, IDisposable
      ContainerControl2 : ScrollableControl2, IContainerControl
         UserControl2 : ContainerControl2

Realmente preferiría trabajarco diseño orientado a objetos, en lugar de en contra.

Respuestas a la pregunta(3)

Su respuesta a la pregunta