C# 如何在AutoScroll设置为false的情况下使用ScrollableControl

C# 如何在AutoScroll设置为false的情况下使用ScrollableControl,c#,winforms,controls,scrollable,C#,Winforms,Controls,Scrollable,我有一个自定义控件,可以在自定义绘制的文档画布上缩放 我尝试使用AutoScroll,但没有得到令人满意的结果。当我将AutoScrollPosition和AutoScrollMinSize设置为背对背(以任何顺序)时,每次缩放更改时都会强制绘制并导致抖动。我假设这是因为当我修改这两个属性时,它正在调用一个更新而不是失效 我现在手动设置水平滚动和垂直滚动属性,并将自动滚动设置为false,这样每次缩放级别或客户端大小更改时: int canvasWidth = (int)Math.Ceiling

我有一个自定义控件,可以在自定义绘制的文档画布上缩放

我尝试使用AutoScroll,但没有得到令人满意的结果。当我将AutoScrollPosition和AutoScrollMinSize设置为背对背(以任何顺序)时,每次缩放更改时都会强制绘制并导致抖动。我假设这是因为当我修改这两个属性时,它正在调用一个更新而不是失效

我现在手动设置水平滚动和垂直滚动属性,并将自动滚动设置为false,这样每次缩放级别或客户端大小更改时:

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;
但这会导致一些非常不稳定的行为,包括弹出和滚动


我应该如何为OnScroll编写代码?我尝试了base.OnScroll,但当AutoScroll设置为false时,它没有做任何事情。

我通过创建3个子控件来实现自己的自定义滚动:一个HScrollBar、一个VScrollBar和一个面板

我隐藏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));
    }
}
最后,我们可以允许鼠标滚轮事件滚动以下内容:

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

在使用AutoScroll时,这项功能运行得非常好,没有出现任何问题。

我认为您第一次使用它是正确的。首先设置AutoScrollMinSize,然后调用AutoScrollPosition。使用双缓冲面板控制闪烁。我的控制是双缓冲的。它从不闪烁,除非我同时更改AutoScrollMinSize和AutoScrollPosition。