2012-04-23 4 views
6

Mam niestandardową kontrolę, która powiększa niestandardowe płótno dokumentu.Jak używać ScrollableControl z AutoScroll ustawionym na false

Próbowałem używać AutoScroll, ale nie dawało satysfakcjonujących wyników. Gdybym ustawił AutoScrollPosition i AutoScrollMinSize z powrotem na tył (w dowolnej kolejności), wymuszałby malowanie i powodował drgania za każdym razem, gdy zmienia się zoom. Zakładam, że było tak, ponieważ wywołał aktualizację, a nie unieważnił, gdy zmodyfikowałem obie właściwości.

Jestem teraz ręczne ustawienie właściwości HorizontalScroll i VerticalScroll z AutoScroll ustawiona na false jak więc za każdym razem poziom powiększenia lub zmiany rozmiaru klient:

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; 

W tym przypadku FocusPoint jest Struktura PointF, która przechowuje współrzędne mapy bitowej, na której użytkownik jest skupiony (na przykład, kiedy kółko myszy do powiększenia, koncentrują się na bieżącej lokalizacji myszy w tym czasie). Ta funkcja działa w większości przypadków.

Co nie działa to paski przewijania. Jeśli użytkownik spróbuje ręcznie przewinąć, klikając dowolny pasek przewijania, oba powracają do wartości 0. Nie umieszczam ich nigdzie indziej w moim kodzie. Próbowałem pisząc co następuje w metodzie OnScroll():

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

Invalidate(); 

Ale to powoduje pewne bardzo złe zachowanie w tym wylać i przewijanie poza granicami.

Jak mam napisać kod do OnScroll? Próbowałem już base.OnScroll, ale nic nie zrobił, podczas gdy AutoScroll jest ustawiony na false.

+0

Myślę, że dobrze się spisałeś po raz pierwszy. Najpierw ustaw AutoScrollMinSize, a następnie wywołaj AutoScrollPosition. Użyj podwójnie buforowanego panelu, aby kontrolować migotanie. – LarsTech

+0

Moja kontrola była podwójnie buforowana. Nigdy nie migotała, z wyjątkiem sytuacji, gdy jednocześnie zmieniałem zarówno AutoScrollMinSize, jak i AutoScrollPosition. –

Odpowiedz

3

Skończyłem wdrażanie własnego niestandardowego przewijania, tworząc 3 formanty potomne: HScrollBar, VScrollBar i Panel.

chowam ClientSize i ClientRectangle tak:

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

Układ odbywa się w 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); 
} 

Każdy ScrollBar ma swój Scroll zdarzenia zapisany do następujących:

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

I na koniec możemy może pozwolić zdarzenia rolki myszki do przewijania z następujących czynności:

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

dla niestandardowych malowania, należy użyć następujące oświadczenie:

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

To działało idealnie bez trzasków występujących podczas korzystania AutoScroll.

Powiązane problemy