2012-04-23 8 views
6

Ho un controllo personalizzato che esegue lo zoom su un documento personalizzato disegnato.Come utilizzare ScrollableControl con AutoScroll impostato su false

Ho provato a utilizzare AutoScroll ma non ha dato risultati soddisfacenti. Quando impostassi AutoScrollPosition e AutoScrollMinSize di nuovo in dietro (in qualsiasi ordine) forzerebbe una vernice e causerebbe un jitter ogni volta che lo zoom cambia. Presumo questo perché stava chiamando un aggiornamento e non invalido quando ho modificato entrambe le proprietà.

ora sto impostando manualmente le proprietà HorizontalScroll e VerticalScroll con scorrimento automatico impostato su false in questo modo ogni volta che il livello di zoom o le modifiche di dimensione 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; 

In questo caso, FocusPoint è un Struttura PointF che contiene le coordinate nella bitmap su cui l'utente è focalizzato (ad esempio, quando ruotano il mouse per ingrandire, si stanno concentrando sulla posizione corrente del mouse in quel momento). Questa funzionalità funziona per la maggior parte.

Ciò che non funziona sono le barre di scorrimento. Se l'utente tenta di scorrere manualmente facendo clic su una delle barre di scorrimento, entrambi continuano a tornare a 0. Non li imposto da nessun'altra parte nel mio codice. Ho provato a scrivere quanto segue nel metodo OnScroll():

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

Invalidate(); 

Ma questo provoca un comportamento molto irregolare tra cui sfogliando e lo scorrimento fuori dai limiti.

Come dovrei scrivere il codice per OnScroll? Ho provato la base.OnScroll ma non ha fatto nulla mentre AutoScroll è impostato su false.

+0

Penso che tu abbia avuto ragione la prima volta. Impostare innanzitutto AutoScrollMinSize, quindi chiamare AutoScrollPosition. Utilizzare un pannello a doppio buffer per controllare lo sfarfallio. – LarsTech

+0

Il mio controllo era a doppio buffer. Non ha mai sfarfallato, tranne quando avrei cambiato sia AutoScrollMinSize che AutoScrollPosition allo stesso tempo. –

risposta

3

Ho finito per implementare il mio scorrimento personalizzato creando 3 controlli figlio: un HScrollBar, un VScrollBar e un pannello.

ho nascondere ClientSize e ClientRectangle in questo modo:

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 
     ); 
    } 
} 

Il layout è fatto in 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); 
} 

Ogni ScrollBar ha loro Scroll evento sottoscritto il seguente:

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

E finalmente noi può permettere eventi rotellina del mouse per scorrere con il seguente:

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)); 
    } 
} 

Per verniciatura personalizzata, si potrebbe utilizzare la seguente istruzione:

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

questo ha funzionato perfettamente senza i difetti presenti quando si utilizza AutoScroll.

Problemi correlati