Как использовать ScrollableControl с AutoScroll значение false
у меня есть пользовательский элемент управления, который масштабирует пользовательский холст документа.
Я попытался использовать AutoScroll, но он не давал удовлетворительных результатов. Когда я установил бы AutoScrollPosition и AutoScrollMinSize спина к спине (в любом порядке), это заставило бы краску и вызывало дрожание при каждом изменении масштаба. Я предполагаю, что это было потому, что он вызывал обновление и не аннулировал при изменении обоих свойств.
теперь я вручную устанавливаю HorizontalScroll и Свойства VerticalScroll с Автопрокрутка установлена в 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;
в этом случае FocusPoint - это структура PointF, которая содержит координаты в растровом изображении, на котором фокусируется пользователь (например, когда они вращают колесо мыши для увеличения, они фокусируются на текущем местоположении мыши в это время). Эта функциональность работает по большей части.
что не работает прокрутка палка. Если пользователь пытается вручную прокрутить, нажав на любую полосу прокрутки, они оба продолжают возвращаться к 0. Я не устанавливаю их нигде в своем коде. Я попытался написать следующее в методе OnScroll ():
if (se.ScrollOrientation == ScrollOrientation.VerticalScroll)
{
VerticalScroll.Value = se.NewValue;
}
else
{
HorizontalScroll.Value = se.NewValue;
}
Invalidate();
но это вызывает очень неустойчивое поведение, включая щелчок и прокрутку за пределы.
как я должен написать код для OnScroll? Я пробовал базу.OnScroll, но он ничего не сделал, пока установлен AutoScroll значение false.
1 ответов
в итоге я реализовал свою собственную прокрутку, создав 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);
}
и, наконец, мы можем позволить событиям MouseWheel прокручиваться с помощью следующий:
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.