2012-04-23 25 views
6

カスタム描画されたドキュメントキャンバスをズームするカスタムコントロールがあります。ScrollableControlをAutoScrollをfalseに設定して使用する方法

AutoScrollを使用しようとしましたが、満足のいく結果が得られませんでした。 AutoScrollPositionとAutoScrollMinSizeを(任意の順序で)バック・ツー・バックに設定すると、ペイントが強制され、ズームが変化するたびにジッタが発生します。これは、両方のプロパティを変更したときにUpdateを呼び出していてInvalidateではなかったためです。

ズームレベルまたはクライアントのサイズの変更、私は今、手動でその都度のような偽に自動スクロールセットとHorizo​​ntalScrollとVerticalScrollプロパティを設定しています。この場合

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; 

FocusPointがありますユーザーがフォーカスしているビットマップの座標を保持するPointF構造体(たとえば、マウスホイールをズームインすると、その時点で現在のマウスの位置にフォーカスしている)。この機能はほとんどの場合機能します。

スクロールバーは機能しません。ユーザーがいずれかのスクロールバーをクリックして手動でスクロールしようとすると、両方とも0に戻り続けます。コード内のどこにでも設定しません。

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

Invalidate(); 

しかし、これはフリックや範囲外のスクロールなど、いくつかの非常に不安定動作が発生します。私はOnScroll()メソッドで次のように書いて試してみました。

OnScrollのコードをどのように記述する必要がありますか?私はbase.OnScrollを試しましたが、AutoScrollがfalseに設定されている間は何もしませんでした。

+0

初めての方がいいと思います。最初にAutoScrollMinSizeを設定してから、AutoScrollPositionを呼び出します。フリッカーを制御するには、ダブルバッファーパネルを使用します。 – LarsTech

+0

私のコントロールはダブルバッファーされていました。 AutoScrollMinSizeとAutoScrollPositionの両方を同時に変更する場合を除き、決して点滅しませんでした。 –

答えて

3

HScrollBar、VScrollBar、Panelの3つの子コントロールを作成して、独自のカスタムスクロールを実装しました。

ので、同様に、私はClientSizeとClientRectangleを隠す:

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

レイアウトが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); 
} 

各スクロールバーは、次のようにサブスクライブし、そのスクロールイベントがあります。

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

最後にマウスホイールイベントは、次のようにスクロールできるようにすることができます:

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

カスタムペイントのために、次の文を使用します。

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

これは、自動スクロールを使用した本グリッチなしで完全に働きました。