2012-04-23 16 views
6

Tengo un control personalizado que amplía un lienzo de documento dibujado personalizado.Cómo usar ScrollableControl con AutoScroll establecido en falso

Intenté usar AutoScroll pero no estaba dando resultados satisfactorios. Cuando establecía AutoScrollPosition y AutoScrollMinSize espalda con espalda (en cualquier orden) forzaba una pintura y causaba una trepidación cada vez que cambiaba el zoom. Supongo que esto fue porque estaba llamando a una actualización y no invalidar cuando modifiqué ambas propiedades.

Ahora estoy configuración manual de las propiedades HorizontalScroll y VerticalScroll con conjunto desplazamiento automático en false al igual que cada vez que el nivel de zoom o cambia el tamaño del cliente:

int canvasWidth = (int)Math.Ceiling(Image.Width * Zoom) + PageMargins.Horizontal; 
int canvasHeight = (int)Math.Ceiling(Image.Height * Zoom) + PageMargins.Vertical; 

HorizontalScroll.Maximum = canvasWidth; 
HorizontalScroll.LargeChange = ClientSize.Width; 

VerticalScroll.Maximum = canvasHeight; 
VerticalScroll.LargeChange = ClientSize.Height; 

if (canvasWidth > ClientSize.Width) 
{ 
    HorizontalScroll.Visible = true; 
} 
else 
{ 
    HorizontalScroll.Visible = false; 
    HorizontalScroll.Value = 0; 
} 

if (canvasHeight > ClientSize.Height) 
{ 
    VerticalScroll.Visible = true; 
} 
else 
{ 
    VerticalScroll.Visible = false; 
    VerticalScroll.Value = 0; 
} 

int focusX = (int)Math.Floor((FocusPoint.X * Zoom) + PageMargins.Left); 
int focusY = (int)Math.Floor((FocusPoint.Y * Zoom) + PageMargins.Top); 

focusX = focusX - ClientSize.Width/2; 
focusY = focusY - ClientSize.Height/2; 

if (focusX < 0) 
    focusX = 0; 
if (focusX > canvasWidth - ClientSize.Width) 
    focusX = canvasWidth - ClientSize.Width; 

if (focusY < 0) 
    focusY = 0; 
if (focusY > canvasHeight - ClientSize.Height) 
    focusY = canvasHeight - ClientSize.Height; 

if (HorizontalScroll.Visible) 
    HorizontalScroll.Value = focusX; 

if (VerticalScroll.Visible) 
    VerticalScroll.Value = focusY; 

En este caso, FocusPoint es una Estructura PointF que contiene las coordenadas en el mapa de bits en el que el usuario está enfocado (por ejemplo, cuando la rueda del mouse para acercar se enfoca en la ubicación actual del mouse en ese momento). Esta funcionalidad funciona en su mayor parte.

Lo que no funciona son las barras de desplazamiento. Si el usuario intenta desplazarse manualmente haciendo clic en cualquiera de las barras de desplazamiento, ambos continúan volviendo a 0. No los configuro en ningún otro lugar en mi código. He intentado escribir el siguiente en el método OnScroll():

if (se.ScrollOrientation == ScrollOrientation.VerticalScroll) 
{ 
    VerticalScroll.Value = se.NewValue; 
} 
else 
{ 
    HorizontalScroll.Value = se.NewValue; 
} 

Invalidate(); 

Pero esto provoca un comportamiento muy irregular incluyendo parpadeo y el desplazamiento fuera de límites.

¿Cómo se supone que debo escribir el código para OnScroll? He probado la base. En Desplazamiento, pero no hizo nada mientras AutoScroll está configurado en falso.

+0

Creo que lo hiciste bien la primera vez. Establezca primero AutoScrollMinSize, luego llame a AutoScrollPosition. Use un panel de doble amortiguación para controlar el parpadeo. – LarsTech

+0

Mi control tenía doble buffer. Nunca parpadeó, excepto cuando cambiaba AutoScrollMinSize y AutoScrollPosition al mismo tiempo. –

Respuesta

3

Terminé implementando mi propio desplazamiento personalizado creando 3 controles secundarios: un HScrollBar, un VScrollBar y un Panel.

me escondo ClientSize y ClientRectangle así:

public new Rectangle ClientRectangle 
{ 
    get 
    { 
     return new Rectangle(new Point(0, 0), ClientSize); 
    } 
} 

public new Size ClientSize 
{ 
    get 
    { 
     return new Size(
      base.ClientSize.Width - VScrollBar.Width, 
      base.ClientSize.Height - HScrollBar.Height 
     ); 
    } 
} 

El diseño se hace en OnClientSizeChanged:

protected override void OnClientSizeChanged(EventArgs e) 
{ 
    base.OnClientSizeChanged(e); 

    HScrollBar.Location = new Point(0, base.ClientSize.Height - HScrollBar.Height); 
    HScrollBar.Width = base.ClientSize.Width - VScrollBar.Width; 

    VScrollBar.Location = new Point(base.ClientSize.Width - VScrollBar.Width, 0); 
    VScrollBar.Height = base.ClientSize.Height - HScrollBar.Height; 

    cornerPanel.Size = new Size(VScrollBar.Width, HScrollBar.Height); 
    cornerPanel.Location = new Point(base.ClientSize.Width - cornerPanel.Width, base.ClientSize.Height - cornerPanel.Height); 
} 

Cada ScrollBar tiene su desplazamiento evento suscrito a lo siguiente:

private void ScrollBar_Scroll(object sender, ScrollEventArgs e) 
{ 
    OnScroll(e); 
} 

Y finalmente puede dejar que los acontecimientos rueda del ratón para desplazarse por la siguiente:

protected override void OnMouseWheel(MouseEventArgs e) 
{ 
    int xOldValue = VScrollBar.Value; 

    if (e.Delta > 0) 
    { 
     VScrollBar.Value = (int)Math.Max(VScrollBar.Value - (VScrollBar.SmallChange * e.Delta), 0); 
     OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, xOldValue, VScrollBar.Value, ScrollOrientation.VerticalScroll)); 
    } 
    else 
    { 
     VScrollBar.Value = (int)Math.Min(VScrollBar.Value - (VScrollBar.SmallChange * e.Delta), VScrollBar.Maximum - (VScrollBar.LargeChange - 1)); 
     OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, xOldValue, VScrollBar.Value, ScrollOrientation.VerticalScroll)); 
    } 
} 

Por encargo de la pintura, se utiliza la siguiente declaración:

e.Graphics.TranslateTransform(-HScrollBar.Value, -VScrollBar.Value); 

Esto funcionó perfectamente sin los problemas técnicos presentes cuando se utiliza el desplazamiento automático.

Cuestiones relacionadas