Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / WinForms / Managed / System / WinForms / ScrollableControl.cs / 1 / ScrollableControl.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
/*
*/
namespace System.Windows.Forms {
using System.Runtime.Serialization.Formatters;
using System.Runtime.Remoting;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System;
using System.Security.Permissions;
using System.Reflection;
using System.Windows.Forms.Layout;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using Microsoft.Win32;
///
///
///
/// Defines a base class for controls that support auto-scrolling behavior.
///
///
[
ComVisible(true),
ClassInterface(ClassInterfaceType.AutoDispatch),
Designer("System.Windows.Forms.Design.ScrollableControlDesigner, " + AssemblyRef.SystemDesign)
]
public class ScrollableControl : Control, IArrangedElement {
#if DEBUG
internal static readonly TraceSwitch AutoScrolling = new TraceSwitch("AutoScrolling", "Debug autoscrolling logic");
#else
internal static readonly TraceSwitch AutoScrolling;
#endif
///
///
protected const int ScrollStateAutoScrolling = 0x0001;
///
///
///
///
protected const int ScrollStateHScrollVisible = 0x0002;
///
///
///
///
protected const int ScrollStateVScrollVisible = 0x0004;
///
///
///
///
protected const int ScrollStateUserHasScrolled = 0x0008;
///
///
///
///
protected const int ScrollStateFullDrag = 0x0010;
private Size userAutoScrollMinSize = System.Drawing.Size.Empty;
///
/// Current size of the displayRect.
///
///
private Rectangle displayRect = Rectangle.Empty;
///
/// Current margins for autoscrolling.
///
///
private Size scrollMargin = System.Drawing.Size.Empty;
///
/// User requested margins for autoscrolling.
///
///
private Size requestedScrollMargin = System.Drawing.Size.Empty;
///
/// User requested autoscroll position - used for form creation only.
///
///
internal Point scrollPosition = Point.Empty;
private DockPaddingEdges dockPadding = null;
private int scrollState;
VScrollProperties verticalScroll = null;
HScrollProperties horizontalScroll = null;
private static readonly object EVENT_SCROLL = new object();
// Used to figure out what the horizontal scroll value should be set to when
// the horizontal scrollbar is first shown
private bool resetRTLHScrollValue = false;
///
///
///
/// Initializes a new instance of the class.
///
///
public ScrollableControl()
: base() {
SetStyle(ControlStyles.ContainerControl, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, false);
SetScrollState(ScrollStateAutoScrolling, false);
}
///
///
///
/// Gets
/// or sets a value
/// indicating whether the container will allow the user to scroll to any
/// controls placed outside of its visible boundaries.
///
///
[
SRCategory(SR.CatLayout),
Localizable(true),
DefaultValue(false),
SRDescription(SR.FormAutoScrollDescr)
]
public virtual bool AutoScroll {
get {
return GetScrollState(ScrollStateAutoScrolling);
}
set {
if (value) {
UpdateFullDrag();
}
SetScrollState(ScrollStateAutoScrolling, value);
LayoutTransaction.DoLayout(this, this, PropertyNames.AutoScroll);
}
}
///
///
///
/// Gets or
/// sets the size of the auto-scroll
/// margin.
///
///
[
SRCategory(SR.CatLayout),
Localizable(true),
SRDescription(SR.FormAutoScrollMarginDescr)
]
public Size AutoScrollMargin {
get {
return requestedScrollMargin;
}
set {
if (value.Width < 0 || value.Height < 0) {
throw new ArgumentOutOfRangeException("AutoScrollMargin", SR.GetString(SR.InvalidArgument, "AutoScrollMargin", value.ToString()));
}
SetAutoScrollMargin(value.Width, value.Height);
}
}
///
///
/// Gets or sets the location of the auto-scroll position.
///
[
SRCategory(SR.CatLayout),
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRDescription(SR.FormAutoScrollPositionDescr)
]
public Point AutoScrollPosition {
get {
Rectangle rect = GetDisplayRectInternal();
return new Point(rect.X, rect.Y);
}
set {
if (Created) {
SetDisplayRectLocation(-value.X, -value.Y);
SyncScrollbars(true);
}
scrollPosition = value;
}
}
///
///
/// Gets or sets the mimimum size of the auto-scroll.
///
[
SRCategory(SR.CatLayout),
Localizable(true),
SRDescription(SR.FormAutoScrollMinSizeDescr)
]
public Size AutoScrollMinSize {
get {
return userAutoScrollMinSize;
}
set {
if (value != userAutoScrollMinSize) {
userAutoScrollMinSize = value;
AutoScroll = true;
PerformLayout();
}
}
}
///
///
///
///
/// Retrieves the CreateParams used to create the window.
/// If a subclass overrides this function, it must call the base implementation.
///
///
protected override CreateParams CreateParams {
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
get {
CreateParams cp = base.CreateParams;
if (HScroll || HorizontalScroll.Visible) {
cp.Style |= NativeMethods.WS_HSCROLL;
}
else {
cp.Style &= (~NativeMethods.WS_HSCROLL);
}
if (VScroll || VerticalScroll.Visible) {
cp.Style |= NativeMethods.WS_VSCROLL;
}
else {
cp.Style &= (~NativeMethods.WS_VSCROLL);
}
return cp;
}
}
///
///
///
///
/// Retreives the current display rectangle. The display rectangle
/// is the virtual display area that is used to layout components.
/// The position and dimensions of the Form's display rectangle
/// change during autoScroll.
///
///
public override Rectangle DisplayRectangle {
[SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces")]
get {
Rectangle rect = base.ClientRectangle;
if (!displayRect.IsEmpty) {
rect.X = displayRect.X;
rect.Y = displayRect.Y;
if (HScroll) {
rect.Width = displayRect.Width;
}
if (VScroll) {
rect.Height = displayRect.Height;
}
}
return LayoutUtils.DeflateRect(rect, Padding);
}
}
///
///
Rectangle IArrangedElement.DisplayRectangle {
get {
Rectangle displayRectangle = this.DisplayRectangle;
// V7#79 : Controls anchored the bottom of their container may disappear (be scrunched)
// when scrolling is used.
if(AutoScrollMinSize.Width != 0 && AutoScrollMinSize.Height != 0) {
displayRectangle.Width = Math.Max(displayRectangle.Width, AutoScrollMinSize.Width);
displayRectangle.Height = Math.Max(displayRectangle.Height, AutoScrollMinSize.Height);
}
return displayRectangle;
}
}
///
///
///
/// Gets or
/// sets a value indicating whether the horizontal scroll bar is visible.
///
///
protected bool HScroll {
get {
return GetScrollState(ScrollStateHScrollVisible);
}
set {
SetScrollState(ScrollStateHScrollVisible, value);
}
}
///
///
/// Gets the Horizontal Scroll bar for this ScrollableControl.
///
[
SRCategory(SR.CatLayout),
SRDescription(SR.ScrollableControlHorizontalScrollDescr),
Browsable(false), EditorBrowsable(EditorBrowsableState.Always)
]
public HScrollProperties HorizontalScroll {
get {
if (horizontalScroll == null) {
horizontalScroll = new HScrollProperties(this);
}
return horizontalScroll;
}
}
///
///
///
/// Gets or
/// sets a value indicating whether the vertical scroll bar is visible.
///
///
protected bool VScroll {
get {
return GetScrollState(ScrollStateVScrollVisible);
}
set {
SetScrollState(ScrollStateVScrollVisible, value);
}
}
///
///
/// Gets the Veritcal Scroll bar for this ScrollableControl.
///
[
SRCategory(SR.CatLayout),
SRDescription(SR.ScrollableControlVerticalScrollDescr),
Browsable(false), EditorBrowsable(EditorBrowsableState.Always)
]
public VScrollProperties VerticalScroll {
get {
if (verticalScroll == null) {
verticalScroll = new VScrollProperties(this);
}
return verticalScroll;
}
}
///
///
/// Gets the dock padding settings for all
/// edges of the control.
///
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never)
]
public DockPaddingEdges DockPadding {
get {
if (dockPadding == null) {
dockPadding = new DockPaddingEdges(this);
}
return dockPadding;
}
}
///
///
///
/// Adjusts
/// the auto-scroll bars on the container based on the current control
/// positions and the control currently selected.
///
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void AdjustFormScrollbars(bool displayScrollbars) {
bool needLayout = false;
Rectangle display = GetDisplayRectInternal();
if (!displayScrollbars && (HScroll || VScroll)) {
needLayout = SetVisibleScrollbars(false, false);
}
if (!displayScrollbars) {
Rectangle client = ClientRectangle;
display.Width = client.Width;
display.Height = client.Height;
}
else {
needLayout |= ApplyScrollbarChanges(display);
}
if (needLayout) {
LayoutTransaction.DoLayout(this, this, PropertyNames.DisplayRectangle);
}
}
private bool ApplyScrollbarChanges(Rectangle display) {
Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, GetType().Name + "::ApplyScrollbarChanges(" + display + ") {");
Debug.Indent();
bool needLayout = false;
bool needHscroll = false;
bool needVscroll = false;
Rectangle currentClient = ClientRectangle;
Rectangle fullClient = currentClient;
Rectangle minClient = fullClient;
if (HScroll) {
fullClient.Height += SystemInformation.HorizontalScrollBarHeight;
}
else {
minClient.Height -= SystemInformation.HorizontalScrollBarHeight;
}
if (VScroll) {
fullClient.Width += SystemInformation.VerticalScrollBarWidth;
}
else {
minClient.Width -= SystemInformation.VerticalScrollBarWidth;
}
int maxX = minClient.Width;
int maxY = minClient.Height;
if (Controls.Count != 0) {
// Compute the actual scroll margins (take into account docked
// things.)
//
scrollMargin = requestedScrollMargin;
if (dockPadding != null) {
scrollMargin.Height += Padding.Bottom;
scrollMargin.Width += Padding.Right;
}
for (int i=0; i maxX) {
needHscroll = true;
maxX = layoutBounds.Width;
}
if (layoutBounds.Height > maxY) {
needVscroll = true;
maxY = layoutBounds.Height;
}
}
else if (Controls.Count != 0) {
// Compute the dimensions of the display rect
//
for (int i=0; i < Controls.Count; i++) {
bool watchHoriz = true;
bool watchVert = true;
Control current = Controls[i];
// Same logic as the margin calc - you need to see if the
// control *will* be visible...
//
if (current != null && current.GetState(STATE_VISIBLE)) {
if (defaultLayoutEngine) {
Control richCurrent = (Control)current;
switch (richCurrent.Dock) {
case DockStyle.Top:
watchHoriz = false;
break;
case DockStyle.Left:
watchVert = false;
break;
case DockStyle.Bottom:
case DockStyle.Fill:
case DockStyle.Right:
watchHoriz = false;
watchVert = false;
break;
default:
AnchorStyles anchor = richCurrent.Anchor;
if ((anchor & AnchorStyles.Right) == AnchorStyles.Right) {
watchHoriz = false;
}
if ((anchor & AnchorStyles.Left) != AnchorStyles.Left) {
watchHoriz = false;
}
if ((anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom) {
watchVert = false;
}
if ((anchor & AnchorStyles.Top) != AnchorStyles.Top) {
watchVert = false;
}
break;
}
}
if (watchHoriz || watchVert) {
Rectangle bounds = current.Bounds;
int ctlRight = -display.X + bounds.X + bounds.Width + scrollMargin.Width;
int ctlBottom = -display.Y + bounds.Y + bounds.Height + scrollMargin.Height;
if (!defaultLayoutEngine)
{
ctlRight += current.Margin.Right;
ctlBottom += current.Margin.Bottom;
}
if (ctlRight > maxX && watchHoriz) {
needHscroll = true;
maxX = ctlRight;
}
if (ctlBottom > maxY && watchVert) {
needVscroll = true;
maxY = ctlBottom;
}
}
}
}
}
// Check maxX/maxY against the clientRect, we must compare it to the
// clientRect without any scrollbars, and then we can check it against
// the clientRect with the "new" scrollbars. This will make the
// scrollbars show and hide themselves correctly at the boundaries.
//
if (maxX <= fullClient.Width) {
needHscroll = false;
}
if (maxY <= fullClient.Height) {
needVscroll = false;
}
Rectangle clientToBe = fullClient;
if (needHscroll) {
clientToBe.Height -= SystemInformation.HorizontalScrollBarHeight;
}
if (needVscroll) {
clientToBe.Width -= SystemInformation.VerticalScrollBarWidth;
}
if (needHscroll && maxY > clientToBe.Height) {
needVscroll = true;
}
if (needVscroll && maxX > clientToBe.Width) {
needHscroll = true;
}
if (!needHscroll) {
maxX = clientToBe.Width;
}
if (!needVscroll) {
maxY = clientToBe.Height;
}
Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "Current scrollbars(" + HScroll + ", " + VScroll + ")");
Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "Needed scrollbars(" + needHscroll + ", " + needVscroll + ")");
// Show the needed scrollbars
//
needLayout = (SetVisibleScrollbars(needHscroll, needVscroll) || needLayout);
// If needed, adjust the size...
//
if (HScroll || VScroll) {
needLayout = (SetDisplayRectangleSize(maxX, maxY) || needLayout);
}
// Else just update the display rect size... this keeps it as big as the client
// area in a resize scenario
//
else {
SetDisplayRectangleSize(maxX, maxY);
}
// [....] up the scrollbars
//
SyncScrollbars(true);
Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, needLayout ? "Need layout" : "No layout changes");
Debug.Unindent();
Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "}");
return needLayout;
}
private Rectangle GetDisplayRectInternal() {
if (displayRect.IsEmpty) {
displayRect = ClientRectangle;
}
if (!AutoScroll && this.HorizontalScroll.visible == true) {
displayRect = new Rectangle(displayRect.X, displayRect.Y, this.HorizontalScroll.Maximum, this.displayRect.Height);
}
if (!AutoScroll && this.VerticalScroll.visible == true) {
displayRect = new Rectangle(displayRect.X, displayRect.Y, this.displayRect.Width, this.VerticalScroll.Maximum);
}
return displayRect;
}
///
///
///
/// Tests a given scroll state bit to determine if it is set.
///
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected bool GetScrollState(int bit) {
return(bit & scrollState) == bit;
}
///
///
///
/// Forces the layout of any docked or anchored child controls.
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected override void OnLayout(LayoutEventArgs levent) {
// V#33515 - [....], 3/18/1998
// We get into a problem when you change the docking of a control
// with autosizing on. Since the control (affectedControl) has
// already had the dock property changed, adjustFormScrollbars
// treats it as a docked control. However, since base.onLayout
// hasn't been called yet, the bounds of the control haven't been
// changed.
//
// We can't just call base.onLayout() once in this case, since
// adjusting the scrollbars COULD adjust the display area, and
// thus require a new layout. The result is that when you
// affect a control's layout, we are forced to layout twice. There
// isn't any noticible flicker, but this could be a perf problem...
//
if (levent.AffectedControl != null && AutoScroll) {
base.OnLayout(levent);
}
AdjustFormScrollbars(AutoScroll);
base.OnLayout(levent);
}
///
///
///
/// Handles mouse wheel processing for our scrollbars.
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected override void OnMouseWheel(MouseEventArgs e) {
// Favor the vertical scroll bar, since it's the most
// common use. However, if there isn't a vertical
// scroll and the horizontal is on, then wheel it around.
//
if (VScroll) {
Rectangle client = ClientRectangle;
int pos = -displayRect.Y;
int maxPos = -(client.Height - displayRect.Height);
pos = Math.Max(pos - e.Delta, 0);
pos = Math.Min(pos, maxPos);
SetDisplayRectLocation(displayRect.X, -pos);
SyncScrollbars(AutoScroll);
if (e is HandledMouseEventArgs)
{
((HandledMouseEventArgs)e).Handled = true;
}
}
else if (HScroll) {
Rectangle client = ClientRectangle;
int pos = -displayRect.X;
int maxPos = -(client.Width - displayRect.Width);
pos = Math.Max(pos - e.Delta, 0);
pos = Math.Min(pos, maxPos);
SetDisplayRectLocation(-pos, displayRect.Y);
SyncScrollbars(AutoScroll);
if (e is HandledMouseEventArgs)
{
((HandledMouseEventArgs)e).Handled = true;
}
}
// The base implementation should be called before the implementation above,
// but changing the order in Whidbey would be too much of a breaking change
// for this particular class.
base.OnMouseWheel(e);
}
///
///
/// [To be supplied.]
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected override void OnRightToLeftChanged(EventArgs e) {
base.OnRightToLeftChanged(e);
resetRTLHScrollValue = true;
// When the page becomes visible, we need to call OnLayout to adjust the scrollbars.
LayoutTransaction.DoLayout(this, this, PropertyNames.RightToLeft);
}
///
protected override void OnPaintBackground (PaintEventArgs e) {
if ((HScroll || VScroll) &&
BackgroundImage != null &&
(BackgroundImageLayout == ImageLayout.Zoom || BackgroundImageLayout == ImageLayout.Stretch || BackgroundImageLayout == ImageLayout.Center)) {
if (ControlPaint.IsImageTransparent(BackgroundImage)) {
PaintTransparentBackground(e, displayRect);
}
ControlPaint.DrawBackgroundImage(e.Graphics, BackgroundImage, BackColor, BackgroundImageLayout, displayRect, displayRect, displayRect.Location);
}
else {
base.OnPaintBackground(e);
}
}
protected override void OnPaddingChanged(EventArgs e) {
// VSWhidbey 340011: DockPaddingEdges compat.
// dont call base in this instance - for App compat we should not fire Invalidate when
// the padding has changed.
EventHandler handler = (EventHandler)Events[Control.EventPaddingChanged];
if (handler != null) handler(this, e);
}
///
///
/// [To be supplied.]
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected override void OnVisibleChanged(EventArgs e) {
if (Visible) {
// When the page becomes visible, we need to call OnLayout to adjust the scrollbars.
LayoutTransaction.DoLayout(this, this, PropertyNames.Visible);
}
base.OnVisibleChanged(e);
}
// internal for Form to call
//
internal void ScaleDockPadding(float dx, float dy) {
if (dockPadding != null) {
dockPadding.Scale(dx, dy);
}
}
///
[EditorBrowsable(EditorBrowsableState.Never)]
protected override void ScaleCore(float dx, float dy) {
ScaleDockPadding(dx, dy);
base.ScaleCore(dx, dy);
}
///
///
/// Scale this form. Form overrides this to enforce a maximum / minimum size.
///
protected override void ScaleControl(SizeF factor, BoundsSpecified specified) {
ScaleDockPadding(factor.Width, factor.Height);
base.ScaleControl(factor, specified);
}
// internal for the respective scroll bars to call so that the Display Rectangle is set to
// enable the visual scroll effect.
//
internal void SetDisplayFromScrollProps(int x, int y)
{
Rectangle display = GetDisplayRectInternal();
ApplyScrollbarChanges(display);
SetDisplayRectLocation(x, y);
}
///
///
/// Adjusts the displayRect to be at the offset x, y. The contents of the
/// Form is scrolled using Windows.ScrollWindowEx.
///
//
//
protected void SetDisplayRectLocation(int x, int y) {
int xDelta = 0;
int yDelta = 0;
Rectangle client = ClientRectangle;
//VSWhidbey 141644 - The DisplayRect property modifies
// the returned rect to include padding. We don't want to
// include this padding in our adjustment of the DisplayRect
// because it interferes with the scrolling.
Rectangle displayRectangle = displayRect;
int minX = Math.Min(client.Width - displayRectangle.Width, 0);
int minY = Math.Min(client.Height - displayRectangle.Height, 0);
if (x > 0) {
x = 0;
}
if (y > 0) {
y = 0;
}
if (x < minX) {
x = minX;
}
if (y < minY) {
y = minY;
}
if (displayRectangle.X != x)
{
xDelta = x - displayRectangle.X;
}
if (displayRectangle.Y != y)
{
yDelta = y - displayRectangle.Y;
}
displayRect.X = x;
displayRect.Y = y;
if (xDelta != 0 || yDelta != 0 && IsHandleCreated) {
Rectangle cr = ClientRectangle;
NativeMethods.RECT rcClip = NativeMethods.RECT.FromXYWH(cr.X, cr.Y, cr.Width, cr.Height);
NativeMethods.RECT rcUpdate = NativeMethods.RECT.FromXYWH(cr.X, cr.Y, cr.Width, cr.Height);
SafeNativeMethods.ScrollWindowEx(new HandleRef(this, Handle), xDelta, yDelta,
null,
ref rcClip,
NativeMethods.NullHandleRef,
ref rcUpdate,
NativeMethods.SW_INVALIDATE
| NativeMethods.SW_ERASE
| NativeMethods.SW_SCROLLCHILDREN);
}
// Force child controls to update bounds.
//
for (int i=0; i
///
/// Scrolls the currently active control into view if we are an AutoScroll
/// Form that has the Horiz or Vert scrollbar displayed...
///
public void ScrollControlIntoView(Control activeControl) {
Debug.WriteLineIf(ScrollableControl.AutoScrolling.TraceVerbose, "ScrollControlIntoView(" + activeControl.GetType().FullName + ")");
Debug.Indent();
Rectangle client = ClientRectangle;
if (IsDescendant(activeControl)
&& AutoScroll
&& (HScroll || VScroll)
&& activeControl != null
&& (client.Width > 0 && client.Height > 0)) {
Debug.WriteLineIf(ScrollableControl.AutoScrolling.TraceVerbose, "Calculating...");
Point scrollLocation = ScrollToControl(activeControl);
SetScrollState(ScrollStateUserHasScrolled, false);
SetDisplayRectLocation(scrollLocation.X, scrollLocation.Y);
SyncScrollbars(true);
}
Debug.Unindent();
}
/// DCR 194760: allow containers to tweak autoscrolling. when you tab between controls contained in the scrollable control
/// this allows you to set the scroll location. This would allow you to scroll to the middle of a control, where as the default is
/// the top of the control.
///
/// Additionally there is a new AutoScrollOffset property on the child controls themselves. This lets them control where they want to
/// be scrolled to. E.g. In SelectedIndexChanged for a ListBox, you could do:
///
/// listBox1.AutoScrollOffset = parent.AutoScrollPosition;
///
///
protected virtual Point ScrollToControl(Control activeControl) {
Rectangle client = ClientRectangle;
int xCalc = displayRect.X;
int yCalc = displayRect.Y;
int xMargin = scrollMargin.Width;
int yMargin = scrollMargin.Height;
Rectangle bounds = activeControl.Bounds;
if (activeControl.ParentInternal != this) {
Debug.WriteLineIf(ScrollableControl.AutoScrolling.TraceVerbose, "not direct child, original bounds: " + bounds);
bounds = this.RectangleToClient(activeControl.ParentInternal.RectangleToScreen(bounds));
}
Debug.WriteLineIf(ScrollableControl.AutoScrolling.TraceVerbose, "adjusted bounds: " + bounds);
if (bounds.X < xMargin) {
xCalc = displayRect.X + xMargin - bounds.X;
}
else if (bounds.X + bounds.Width + xMargin > client.Width) {
xCalc = client.Width - (bounds.X + bounds.Width + xMargin - displayRect.X);
if (bounds.X + xCalc - displayRect.X < xMargin) {
xCalc = displayRect.X + xMargin - bounds.X;
}
}
if (bounds.Y < yMargin) {
yCalc = displayRect.Y + yMargin - bounds.Y;
}
else if (bounds.Y + bounds.Height + yMargin > client.Height) {
yCalc = client.Height - (bounds.Y + bounds.Height + yMargin - displayRect.Y);
if (bounds.Y + yCalc - displayRect.Y < yMargin) {
yCalc = displayRect.Y + yMargin - bounds.Y;
}
}
xCalc += activeControl.AutoScrollOffset.X;
yCalc += activeControl.AutoScrollOffset.Y;
return new Point(xCalc, yCalc);
}
private int ScrollThumbPosition(int fnBar) {
NativeMethods.SCROLLINFO si = new NativeMethods.SCROLLINFO();
si.fMask = NativeMethods.SIF_TRACKPOS;
SafeNativeMethods.GetScrollInfo(new HandleRef(this, Handle), fnBar, si);
return si.nTrackPos;
}
///
///
///
/// Occurs when the scroll box has been moved by either a mouse or keyboard action.
///
///
[SRCategory(SR.CatAction), SRDescription(SR.ScrollBarOnScrollDescr)]
public event ScrollEventHandler Scroll {
add {
Events.AddHandler(EVENT_SCROLL, value);
}
remove {
Events.RemoveHandler(EVENT_SCROLL, value);
}
}
///
///
///
/// Raises the event.
///
///
protected virtual void OnScroll(ScrollEventArgs se) {
ScrollEventHandler handler = (ScrollEventHandler)Events[EVENT_SCROLL];
if (handler != null) handler(this,se);
}
private void ResetAutoScrollMargin() {
AutoScrollMargin = Size.Empty;
}
private void ResetAutoScrollMinSize() {
AutoScrollMinSize = Size.Empty;
}
private void ResetScrollProperties(ScrollProperties scrollProperties) {
// Set only these two values as when the ScrollBars are not visible ...
// there is no meaning of the "value" property.
scrollProperties.visible = false;
scrollProperties.value = 0;
}
///
///
///
/// Sets the size
/// of the auto-scroll margins.
///
///
public void SetAutoScrollMargin(int x, int y) {
// Make sure we're not setting the margins to negative numbers
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
if (x != requestedScrollMargin.Width
|| y != requestedScrollMargin.Height) {
requestedScrollMargin = new Size(x, y);
if (AutoScroll) {
PerformLayout();
}
}
}
///
/// Actually displays or hides the horiz and vert autoscrollbars. This will
/// also adjust the values of formState to reflect the new state
///
private bool SetVisibleScrollbars(bool horiz, bool vert) {
bool needLayout = false;
if (!horiz && HScroll
|| horiz && !HScroll
|| !vert && VScroll
|| vert && !VScroll) {
needLayout = true;
}
// If we are about to show the horizontal scrollbar, then
// set this flag, so that we can set the right initial value
// based on whether we are right to left.
if (horiz && !HScroll && (RightToLeft == RightToLeft.Yes)) {
resetRTLHScrollValue = true;
}
if (needLayout) {
int x = displayRect.X;
int y = displayRect.Y;
if (!horiz) {
x = 0;
}
if (!vert) {
y = 0;
}
SetDisplayRectLocation(x, y);
SetScrollState(ScrollStateUserHasScrolled, false);
HScroll = horiz;
VScroll = vert;
//Update the visible member of ScrollBars....
if (horiz)
{
HorizontalScroll.visible = true;
}
else
{
ResetScrollProperties(HorizontalScroll);
}
if (vert)
{
VerticalScroll.visible = true;
}
else
{
ResetScrollProperties(VerticalScroll);
}
UpdateStyles();
}
return needLayout;
}
///
/// Sets the width and height of the virtual client area used in
/// autoscrolling. This will also adjust the x and y location of the
/// virtual client area if the new size forces it.
///
///
private bool SetDisplayRectangleSize(int width, int height) {
bool needLayout = false;
if (displayRect.Width != width
|| displayRect.Height != height) {
displayRect.Width = width;
displayRect.Height = height;
needLayout = true;
}
int minX = ClientRectangle.Width - width;
int minY = ClientRectangle.Height - height;
if (minX > 0) minX = 0;
if (minY > 0) minY = 0;
int x = displayRect.X;
int y = displayRect.Y;
if (!HScroll) {
x = 0;
}
if (!VScroll) {
y = 0;
}
if (x < minX) {
x = minX;
}
if (y < minY) {
y = minY;
}
SetDisplayRectLocation(x, y);
return needLayout;
}
///
///
///
/// Sets a given scroll state bit.
///
///
protected void SetScrollState(int bit, bool value) {
if (value) {
scrollState |= bit;
}
else {
scrollState &= (~bit);
}
}
///
///
/// Indicates whether the
/// property should be persisted.
///
///
private bool ShouldSerializeAutoScrollPosition() {
if (AutoScroll) {
Point pt = AutoScrollPosition;
if (pt.X != 0 || pt.Y != 0) {
return true;
}
}
return false;
}
///
///
/// Indicates whether the property should be persisted.
///
///
private bool ShouldSerializeAutoScrollMargin() {
return !AutoScrollMargin.Equals(new Size(0,0));
}
///
///
/// Indicates whether the
/// property should be persisted.
///
///
private bool ShouldSerializeAutoScrollMinSize() {
return !AutoScrollMinSize.Equals(new Size(0,0));
}
///
/// Updates the value of the autoscroll scrollbars based on the current form
/// state. This is a one-way [....], updating the scrollbars only.
///
///
private void SyncScrollbars(bool autoScroll) {
Rectangle displayRect = this.displayRect;
if (autoScroll) {
if (!IsHandleCreated) {
return;
}
if (HScroll) {
if (!HorizontalScroll.maximumSetExternally) {
HorizontalScroll.maximum = displayRect.Width-1;
}
if (!HorizontalScroll.largeChangeSetExternally) {
HorizontalScroll.largeChange = ClientRectangle.Width;
}
if (!HorizontalScroll.smallChangeSetExternally) {
HorizontalScroll.smallChange = 5;
}
if (resetRTLHScrollValue && !IsMirrored) {
resetRTLHScrollValue = false;
BeginInvoke(new EventHandler(this.OnSetScrollPosition));
}
else if(-displayRect.X >= HorizontalScroll.minimum && -displayRect.X < HorizontalScroll.maximum) {
HorizontalScroll.value = -displayRect.X;
}
HorizontalScroll.UpdateScrollInfo ();
}
if (VScroll) {
if (!VerticalScroll.maximumSetExternally) {
VerticalScroll.maximum = displayRect.Height-1;
}
if (!VerticalScroll.largeChangeSetExternally) {
VerticalScroll.largeChange = ClientRectangle.Height;
}
if (!VerticalScroll.smallChangeSetExternally) {
VerticalScroll.smallChange = 5;
}
if (-displayRect.Y >= VerticalScroll.minimum && -displayRect.Y < VerticalScroll.maximum) {
VerticalScroll.value = -displayRect.Y;
}
VerticalScroll.UpdateScrollInfo ();
}
}
else {
if (this.HorizontalScroll.Visible) {
HorizontalScroll.Value = -displayRect.X;
}
else {
ResetScrollProperties(HorizontalScroll);
}
if (this.VerticalScroll.Visible) {
VerticalScroll.Value = -displayRect.Y;
}
else {
ResetScrollProperties(VerticalScroll);
}
}
}
private void OnSetScrollPosition(object sender, EventArgs e) {
if (!IsMirrored) {
SendMessage(NativeMethods.WM_HSCROLL,
NativeMethods.Util.MAKELPARAM((RightToLeft == RightToLeft.Yes) ? NativeMethods.SB_RIGHT : NativeMethods.SB_LEFT,0), 0);
}
}
///
/// Queries the system to determine the users preference for full drag
/// of windows.
///
private void UpdateFullDrag() {
SetScrollState(ScrollStateFullDrag, SystemInformation.DragFullWindows);
}
///
/// WM_VSCROLL handler
///
///
private void WmVScroll(ref Message m) {
// The lparam is handle of the sending scrollbar, or NULL when
// the scrollbar sending the message is the "form" scrollbar...
//
if (m.LParam != IntPtr.Zero) {
base.WndProc(ref m);
return;
}
Rectangle client = ClientRectangle;
bool thumbTrack = NativeMethods.Util.LOWORD(m.WParam) != NativeMethods.SB_THUMBTRACK;
int pos = -displayRect.Y;
int oldValue = pos;
int maxPos = -(client.Height - displayRect.Height);
if (!AutoScroll) {
maxPos = this.VerticalScroll.Maximum;
}
switch (NativeMethods.Util.LOWORD(m.WParam)) {
case NativeMethods.SB_THUMBPOSITION:
case NativeMethods.SB_THUMBTRACK:
pos = ScrollThumbPosition(NativeMethods.SB_VERT);
break;
case NativeMethods.SB_LINEUP:
if (pos > 0) {
pos-=VerticalScroll.SmallChange;
}
else {
pos = 0;
}
break;
case NativeMethods.SB_LINEDOWN:
if (pos < maxPos-VerticalScroll.SmallChange) {
pos+=VerticalScroll.SmallChange;
}
else {
pos = maxPos;
}
break;
case NativeMethods.SB_PAGEUP:
if (pos > VerticalScroll.LargeChange) {
pos-=VerticalScroll.LargeChange;
}
else {
pos = 0;
}
break;
case NativeMethods.SB_PAGEDOWN:
if (pos < maxPos-VerticalScroll.LargeChange) {
pos+=VerticalScroll.LargeChange;
}
else {
pos = maxPos;
}
break;
case NativeMethods.SB_TOP:
pos = 0;
break;
case NativeMethods.SB_BOTTOM:
pos = maxPos;
break;
}
// VsW: 178279: This bugs reproes on all those machine which have SystemInformation.DragFullWindows set to false
// "thumbTrack" was incorrectly used... the usage should be identical to WnHScroll which follows.
if (GetScrollState(ScrollStateFullDrag) || thumbTrack ) {
SetScrollState(ScrollStateUserHasScrolled, true);
SetDisplayRectLocation(displayRect.X, -pos);
SyncScrollbars(AutoScroll);
}
WmOnScroll(ref m, oldValue, pos, ScrollOrientation.VerticalScroll);
}
///
/// WM_HSCROLL handler
///
///
private void WmHScroll(ref Message m) {
// The lparam is handle of the sending scrollbar, or NULL when
// the scrollbar sending the message is the "form" scrollbar...
//
if (m.LParam != IntPtr.Zero) {
base.WndProc(ref m);
return;
}
Rectangle client = ClientRectangle;
int pos = -displayRect.X;
int oldValue = pos;
int maxPos = -(client.Width - displayRect.Width);
if (!AutoScroll) {
maxPos = this.HorizontalScroll.Maximum;
}
switch (NativeMethods.Util.LOWORD(m.WParam)) {
case NativeMethods.SB_THUMBPOSITION:
case NativeMethods.SB_THUMBTRACK:
pos = ScrollThumbPosition(NativeMethods.SB_HORZ);
break;
case NativeMethods.SB_LINEUP:
if (pos > HorizontalScroll.SmallChange) {
pos-=HorizontalScroll.SmallChange;
}
else {
pos = 0;
}
break;
case NativeMethods.SB_LINEDOWN:
if (pos < maxPos-HorizontalScroll.SmallChange) {
pos+=HorizontalScroll.SmallChange;
}
else {
pos = maxPos;
}
break;
case NativeMethods.SB_PAGEUP:
if (pos > HorizontalScroll.LargeChange) {
pos-=HorizontalScroll.LargeChange;
}
else {
pos = 0;
}
break;
case NativeMethods.SB_PAGEDOWN:
if (pos < maxPos-HorizontalScroll.LargeChange) {
pos+=HorizontalScroll.LargeChange;
}
else {
pos = maxPos;
}
break;
case NativeMethods.SB_LEFT:
pos = 0;
break;
case NativeMethods.SB_RIGHT:
pos = maxPos;
break;
}
if (GetScrollState(ScrollStateFullDrag) || NativeMethods.Util.LOWORD(m.WParam) != NativeMethods.SB_THUMBTRACK) {
SetScrollState(ScrollStateUserHasScrolled, true);
SetDisplayRectLocation(-pos, displayRect.Y);
SyncScrollbars(AutoScroll);
}
WmOnScroll(ref m, oldValue, pos, ScrollOrientation.HorizontalScroll);
}
///
/// This function gets called which populates the eventArgs and fires the OnScroll( ) event passing
/// the appropriate scroll event and scroll bar.
///
///
private void WmOnScroll(ref Message m, int oldValue, int value, ScrollOrientation scrollOrientation) {
ScrollEventType type = (ScrollEventType)NativeMethods.Util.LOWORD(m.WParam);
if (type != ScrollEventType.EndScroll) {
ScrollEventArgs se = new ScrollEventArgs(type, oldValue, value, scrollOrientation);
OnScroll(se);
}
}
private void WmSettingChange(ref Message m) {
base.WndProc(ref m);
UpdateFullDrag();
}
///
///
/// The button's window procedure. Inheriting classes can override this
/// to add extra functionality, but should not forget to call
/// base.wndProc(m); to ensure the button continues to function properly.
///
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m) {
switch (m.Msg) {
case NativeMethods.WM_VSCROLL:
WmVScroll(ref m);
break;
case NativeMethods.WM_HSCROLL:
WmHScroll(ref m);
break;
case NativeMethods.WM_SETTINGCHANGE:
WmSettingChange(ref m);
break;
default:
base.WndProc(ref m);
break;
}
}
///
///
/// Determines the border padding for
/// docked controls.
///
[TypeConverterAttribute(typeof(DockPaddingEdgesConverter))]
public class DockPaddingEdges : ICloneable {
private ScrollableControl owner;
private int left;
private int right;
private int top;
private int bottom;
///
/// Creates a new DockPaddingEdges. The specified owner will
/// be notified when the values are changed.
///
internal DockPaddingEdges(ScrollableControl owner) {
this.owner = owner;
}
internal DockPaddingEdges(int left, int right, int top, int bottom) {
this.left = left;
this.right = right;
this.top = top;
this.bottom = bottom;
}
///
///
/// Gets
/// or
/// sets the padding width for all edges of a docked control.
///
[
RefreshProperties(RefreshProperties.All),
SRDescription(SR.PaddingAllDescr)
]
public int All {
get {
if (owner == null) {
if (left == right && top == bottom && left == top) {
return left;
}
else {
return 0;
}
}
else {
// The Padding struct uses -1 to indicate that LRTB are in disagreement.
// For backwards compatibility, we need to remap -1 to 0, but we need
// to be careful because it could be that they explicitly set All to -1.
if (owner.Padding.All == -1
&&
(owner.Padding.Left != -1
|| owner.Padding.Top != -1
|| owner.Padding.Right != -1
|| owner.Padding.Bottom != -1)) {
return 0;
}
return owner.Padding.All;
}
}
set {
if (owner == null) {
left = value;
top = value;
right = value;
bottom = value;
}
else {
owner.Padding = new Padding(value);
}
}
}
///
///
/// Gets
/// or
/// sets the padding width for the bottom edge of a docked control.
///
[
RefreshProperties(RefreshProperties.All),
SRDescription(SR.PaddingBottomDescr)
]
public int Bottom {
get {
if (owner == null) {
return bottom;
}
else {
return owner.Padding.Bottom;
}
}
set {
if (owner == null) {
bottom = value;
}
else {
Padding padding = owner.Padding;
padding.Bottom = value;
owner.Padding = padding;
}
}
}
///
///
/// Gets
/// or sets the padding width for the left edge of a docked control.
///
[
RefreshProperties(RefreshProperties.All),
SRDescription(SR.PaddingLeftDescr)
]
public int Left {
get {
if (owner == null) {
return left;
}
else {
return owner.Padding.Left;
}
}
set {
if (owner == null) {
left = value;
}
else {
Padding padding = owner.Padding;
padding.Left = value;
owner.Padding = padding;
}
}
}
///
///
/// Gets
/// or sets the padding width for the right edge of a docked control.
///
[
RefreshProperties(RefreshProperties.All),
SRDescription(SR.PaddingRightDescr)
]
public int Right {
get {
if (owner == null) {
return right;
}
else {
return owner.Padding.Right;
}
}
set {
if (owner == null) {
right = value;
}
else {
Padding padding = owner.Padding;
padding.Right = value;
owner.Padding = padding;
}
}
}
///
///
/// Gets
/// or sets the padding width for the top edge of a docked control.
///
[
RefreshProperties(RefreshProperties.All),
SRDescription(SR.PaddingTopDescr)
]
public int Top {
get {
if (owner == null) {
return bottom;
}
else {
return owner.Padding.Top;
}
}
set {
if (owner == null) {
top = value;
}
else {
Padding padding = owner.Padding;
padding.Top = value;
owner.Padding = padding;
}
}
}
///
///
public override bool Equals(object other) {
DockPaddingEdges dpeOther = other as DockPaddingEdges;
if (dpeOther != null) {
return this.owner.Padding.Equals(dpeOther.owner.Padding);
}
return false;
}
///
///
public override int GetHashCode() {
return base.GetHashCode();
}
///
private void ResetAll() {
All = 0;
}
///
private void ResetBottom() {
Bottom = 0;
}
///
private void ResetLeft() {
Left = 0;
}
///
private void ResetRight() {
Right = 0;
}
///
private void ResetTop() {
Top = 0;
}
internal void Scale(float dx, float dy) {
this.owner.Padding.Scale(dx, dy);
}
///
///
public override string ToString() {
return ""; // used to say "(DockPadding)" but that's useless
}
///
///
object ICloneable.Clone() {
DockPaddingEdges dpe = new DockPaddingEdges(Left, Right, Top, Bottom);
return dpe;
}
}
///
public class DockPaddingEdgesConverter : TypeConverter {
///
///
/// Retrieves the set of properties for this type. By default, a type has
/// does not return any properties. An easy implementation of this method
/// can just call TypeDescriptor.GetProperties for the correct data type.
///
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) {
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(DockPaddingEdges), attributes);
return props.Sort(new string[] {"All", "Left", "Top", "Right", "Bottom"});
}
///
///
/// Determines if this object supports properties. By default, this
/// is false.
///
public override bool GetPropertiesSupported(ITypeDescriptorContext context) {
return true;
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
/*
*/
namespace System.Windows.Forms {
using System.Runtime.Serialization.Formatters;
using System.Runtime.Remoting;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System;
using System.Security.Permissions;
using System.Reflection;
using System.Windows.Forms.Layout;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using Microsoft.Win32;
///
///
///
/// Defines a base class for controls that support auto-scrolling behavior.
///
///
[
ComVisible(true),
ClassInterface(ClassInterfaceType.AutoDispatch),
Designer("System.Windows.Forms.Design.ScrollableControlDesigner, " + AssemblyRef.SystemDesign)
]
public class ScrollableControl : Control, IArrangedElement {
#if DEBUG
internal static readonly TraceSwitch AutoScrolling = new TraceSwitch("AutoScrolling", "Debug autoscrolling logic");
#else
internal static readonly TraceSwitch AutoScrolling;
#endif
///
///
protected const int ScrollStateAutoScrolling = 0x0001;
///
///
///
///
protected const int ScrollStateHScrollVisible = 0x0002;
///
///
///
///
protected const int ScrollStateVScrollVisible = 0x0004;
///
///
///
///
protected const int ScrollStateUserHasScrolled = 0x0008;
///
///
///
///
protected const int ScrollStateFullDrag = 0x0010;
private Size userAutoScrollMinSize = System.Drawing.Size.Empty;
///
/// Current size of the displayRect.
///
///
private Rectangle displayRect = Rectangle.Empty;
///
/// Current margins for autoscrolling.
///
///
private Size scrollMargin = System.Drawing.Size.Empty;
///
/// User requested margins for autoscrolling.
///
///
private Size requestedScrollMargin = System.Drawing.Size.Empty;
///
/// User requested autoscroll position - used for form creation only.
///
///
internal Point scrollPosition = Point.Empty;
private DockPaddingEdges dockPadding = null;
private int scrollState;
VScrollProperties verticalScroll = null;
HScrollProperties horizontalScroll = null;
private static readonly object EVENT_SCROLL = new object();
// Used to figure out what the horizontal scroll value should be set to when
// the horizontal scrollbar is first shown
private bool resetRTLHScrollValue = false;
///
///
///
/// Initializes a new instance of the class.
///
///
public ScrollableControl()
: base() {
SetStyle(ControlStyles.ContainerControl, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, false);
SetScrollState(ScrollStateAutoScrolling, false);
}
///
///
///
/// Gets
/// or sets a value
/// indicating whether the container will allow the user to scroll to any
/// controls placed outside of its visible boundaries.
///
///
[
SRCategory(SR.CatLayout),
Localizable(true),
DefaultValue(false),
SRDescription(SR.FormAutoScrollDescr)
]
public virtual bool AutoScroll {
get {
return GetScrollState(ScrollStateAutoScrolling);
}
set {
if (value) {
UpdateFullDrag();
}
SetScrollState(ScrollStateAutoScrolling, value);
LayoutTransaction.DoLayout(this, this, PropertyNames.AutoScroll);
}
}
///
///
///
/// Gets or
/// sets the size of the auto-scroll
/// margin.
///
///
[
SRCategory(SR.CatLayout),
Localizable(true),
SRDescription(SR.FormAutoScrollMarginDescr)
]
public Size AutoScrollMargin {
get {
return requestedScrollMargin;
}
set {
if (value.Width < 0 || value.Height < 0) {
throw new ArgumentOutOfRangeException("AutoScrollMargin", SR.GetString(SR.InvalidArgument, "AutoScrollMargin", value.ToString()));
}
SetAutoScrollMargin(value.Width, value.Height);
}
}
///
///
/// Gets or sets the location of the auto-scroll position.
///
[
SRCategory(SR.CatLayout),
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRDescription(SR.FormAutoScrollPositionDescr)
]
public Point AutoScrollPosition {
get {
Rectangle rect = GetDisplayRectInternal();
return new Point(rect.X, rect.Y);
}
set {
if (Created) {
SetDisplayRectLocation(-value.X, -value.Y);
SyncScrollbars(true);
}
scrollPosition = value;
}
}
///
///
/// Gets or sets the mimimum size of the auto-scroll.
///
[
SRCategory(SR.CatLayout),
Localizable(true),
SRDescription(SR.FormAutoScrollMinSizeDescr)
]
public Size AutoScrollMinSize {
get {
return userAutoScrollMinSize;
}
set {
if (value != userAutoScrollMinSize) {
userAutoScrollMinSize = value;
AutoScroll = true;
PerformLayout();
}
}
}
///
///
///
///
/// Retrieves the CreateParams used to create the window.
/// If a subclass overrides this function, it must call the base implementation.
///
///
protected override CreateParams CreateParams {
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
get {
CreateParams cp = base.CreateParams;
if (HScroll || HorizontalScroll.Visible) {
cp.Style |= NativeMethods.WS_HSCROLL;
}
else {
cp.Style &= (~NativeMethods.WS_HSCROLL);
}
if (VScroll || VerticalScroll.Visible) {
cp.Style |= NativeMethods.WS_VSCROLL;
}
else {
cp.Style &= (~NativeMethods.WS_VSCROLL);
}
return cp;
}
}
///
///
///
///
/// Retreives the current display rectangle. The display rectangle
/// is the virtual display area that is used to layout components.
/// The position and dimensions of the Form's display rectangle
/// change during autoScroll.
///
///
public override Rectangle DisplayRectangle {
[SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces")]
get {
Rectangle rect = base.ClientRectangle;
if (!displayRect.IsEmpty) {
rect.X = displayRect.X;
rect.Y = displayRect.Y;
if (HScroll) {
rect.Width = displayRect.Width;
}
if (VScroll) {
rect.Height = displayRect.Height;
}
}
return LayoutUtils.DeflateRect(rect, Padding);
}
}
///
///
Rectangle IArrangedElement.DisplayRectangle {
get {
Rectangle displayRectangle = this.DisplayRectangle;
// V7#79 : Controls anchored the bottom of their container may disappear (be scrunched)
// when scrolling is used.
if(AutoScrollMinSize.Width != 0 && AutoScrollMinSize.Height != 0) {
displayRectangle.Width = Math.Max(displayRectangle.Width, AutoScrollMinSize.Width);
displayRectangle.Height = Math.Max(displayRectangle.Height, AutoScrollMinSize.Height);
}
return displayRectangle;
}
}
///
///
///
/// Gets or
/// sets a value indicating whether the horizontal scroll bar is visible.
///
///
protected bool HScroll {
get {
return GetScrollState(ScrollStateHScrollVisible);
}
set {
SetScrollState(ScrollStateHScrollVisible, value);
}
}
///
///
/// Gets the Horizontal Scroll bar for this ScrollableControl.
///
[
SRCategory(SR.CatLayout),
SRDescription(SR.ScrollableControlHorizontalScrollDescr),
Browsable(false), EditorBrowsable(EditorBrowsableState.Always)
]
public HScrollProperties HorizontalScroll {
get {
if (horizontalScroll == null) {
horizontalScroll = new HScrollProperties(this);
}
return horizontalScroll;
}
}
///
///
///
/// Gets or
/// sets a value indicating whether the vertical scroll bar is visible.
///
///
protected bool VScroll {
get {
return GetScrollState(ScrollStateVScrollVisible);
}
set {
SetScrollState(ScrollStateVScrollVisible, value);
}
}
///
///
/// Gets the Veritcal Scroll bar for this ScrollableControl.
///
[
SRCategory(SR.CatLayout),
SRDescription(SR.ScrollableControlVerticalScrollDescr),
Browsable(false), EditorBrowsable(EditorBrowsableState.Always)
]
public VScrollProperties VerticalScroll {
get {
if (verticalScroll == null) {
verticalScroll = new VScrollProperties(this);
}
return verticalScroll;
}
}
///
///
/// Gets the dock padding settings for all
/// edges of the control.
///
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never)
]
public DockPaddingEdges DockPadding {
get {
if (dockPadding == null) {
dockPadding = new DockPaddingEdges(this);
}
return dockPadding;
}
}
///
///
///
/// Adjusts
/// the auto-scroll bars on the container based on the current control
/// positions and the control currently selected.
///
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void AdjustFormScrollbars(bool displayScrollbars) {
bool needLayout = false;
Rectangle display = GetDisplayRectInternal();
if (!displayScrollbars && (HScroll || VScroll)) {
needLayout = SetVisibleScrollbars(false, false);
}
if (!displayScrollbars) {
Rectangle client = ClientRectangle;
display.Width = client.Width;
display.Height = client.Height;
}
else {
needLayout |= ApplyScrollbarChanges(display);
}
if (needLayout) {
LayoutTransaction.DoLayout(this, this, PropertyNames.DisplayRectangle);
}
}
private bool ApplyScrollbarChanges(Rectangle display) {
Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, GetType().Name + "::ApplyScrollbarChanges(" + display + ") {");
Debug.Indent();
bool needLayout = false;
bool needHscroll = false;
bool needVscroll = false;
Rectangle currentClient = ClientRectangle;
Rectangle fullClient = currentClient;
Rectangle minClient = fullClient;
if (HScroll) {
fullClient.Height += SystemInformation.HorizontalScrollBarHeight;
}
else {
minClient.Height -= SystemInformation.HorizontalScrollBarHeight;
}
if (VScroll) {
fullClient.Width += SystemInformation.VerticalScrollBarWidth;
}
else {
minClient.Width -= SystemInformation.VerticalScrollBarWidth;
}
int maxX = minClient.Width;
int maxY = minClient.Height;
if (Controls.Count != 0) {
// Compute the actual scroll margins (take into account docked
// things.)
//
scrollMargin = requestedScrollMargin;
if (dockPadding != null) {
scrollMargin.Height += Padding.Bottom;
scrollMargin.Width += Padding.Right;
}
for (int i=0; i maxX) {
needHscroll = true;
maxX = layoutBounds.Width;
}
if (layoutBounds.Height > maxY) {
needVscroll = true;
maxY = layoutBounds.Height;
}
}
else if (Controls.Count != 0) {
// Compute the dimensions of the display rect
//
for (int i=0; i < Controls.Count; i++) {
bool watchHoriz = true;
bool watchVert = true;
Control current = Controls[i];
// Same logic as the margin calc - you need to see if the
// control *will* be visible...
//
if (current != null && current.GetState(STATE_VISIBLE)) {
if (defaultLayoutEngine) {
Control richCurrent = (Control)current;
switch (richCurrent.Dock) {
case DockStyle.Top:
watchHoriz = false;
break;
case DockStyle.Left:
watchVert = false;
break;
case DockStyle.Bottom:
case DockStyle.Fill:
case DockStyle.Right:
watchHoriz = false;
watchVert = false;
break;
default:
AnchorStyles anchor = richCurrent.Anchor;
if ((anchor & AnchorStyles.Right) == AnchorStyles.Right) {
watchHoriz = false;
}
if ((anchor & AnchorStyles.Left) != AnchorStyles.Left) {
watchHoriz = false;
}
if ((anchor & AnchorStyles.Bottom) == AnchorStyles.Bottom) {
watchVert = false;
}
if ((anchor & AnchorStyles.Top) != AnchorStyles.Top) {
watchVert = false;
}
break;
}
}
if (watchHoriz || watchVert) {
Rectangle bounds = current.Bounds;
int ctlRight = -display.X + bounds.X + bounds.Width + scrollMargin.Width;
int ctlBottom = -display.Y + bounds.Y + bounds.Height + scrollMargin.Height;
if (!defaultLayoutEngine)
{
ctlRight += current.Margin.Right;
ctlBottom += current.Margin.Bottom;
}
if (ctlRight > maxX && watchHoriz) {
needHscroll = true;
maxX = ctlRight;
}
if (ctlBottom > maxY && watchVert) {
needVscroll = true;
maxY = ctlBottom;
}
}
}
}
}
// Check maxX/maxY against the clientRect, we must compare it to the
// clientRect without any scrollbars, and then we can check it against
// the clientRect with the "new" scrollbars. This will make the
// scrollbars show and hide themselves correctly at the boundaries.
//
if (maxX <= fullClient.Width) {
needHscroll = false;
}
if (maxY <= fullClient.Height) {
needVscroll = false;
}
Rectangle clientToBe = fullClient;
if (needHscroll) {
clientToBe.Height -= SystemInformation.HorizontalScrollBarHeight;
}
if (needVscroll) {
clientToBe.Width -= SystemInformation.VerticalScrollBarWidth;
}
if (needHscroll && maxY > clientToBe.Height) {
needVscroll = true;
}
if (needVscroll && maxX > clientToBe.Width) {
needHscroll = true;
}
if (!needHscroll) {
maxX = clientToBe.Width;
}
if (!needVscroll) {
maxY = clientToBe.Height;
}
Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "Current scrollbars(" + HScroll + ", " + VScroll + ")");
Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "Needed scrollbars(" + needHscroll + ", " + needVscroll + ")");
// Show the needed scrollbars
//
needLayout = (SetVisibleScrollbars(needHscroll, needVscroll) || needLayout);
// If needed, adjust the size...
//
if (HScroll || VScroll) {
needLayout = (SetDisplayRectangleSize(maxX, maxY) || needLayout);
}
// Else just update the display rect size... this keeps it as big as the client
// area in a resize scenario
//
else {
SetDisplayRectangleSize(maxX, maxY);
}
// [....] up the scrollbars
//
SyncScrollbars(true);
Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, needLayout ? "Need layout" : "No layout changes");
Debug.Unindent();
Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "}");
return needLayout;
}
private Rectangle GetDisplayRectInternal() {
if (displayRect.IsEmpty) {
displayRect = ClientRectangle;
}
if (!AutoScroll && this.HorizontalScroll.visible == true) {
displayRect = new Rectangle(displayRect.X, displayRect.Y, this.HorizontalScroll.Maximum, this.displayRect.Height);
}
if (!AutoScroll && this.VerticalScroll.visible == true) {
displayRect = new Rectangle(displayRect.X, displayRect.Y, this.displayRect.Width, this.VerticalScroll.Maximum);
}
return displayRect;
}
///
///
///
/// Tests a given scroll state bit to determine if it is set.
///
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected bool GetScrollState(int bit) {
return(bit & scrollState) == bit;
}
///
///
///
/// Forces the layout of any docked or anchored child controls.
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected override void OnLayout(LayoutEventArgs levent) {
// V#33515 - [....], 3/18/1998
// We get into a problem when you change the docking of a control
// with autosizing on. Since the control (affectedControl) has
// already had the dock property changed, adjustFormScrollbars
// treats it as a docked control. However, since base.onLayout
// hasn't been called yet, the bounds of the control haven't been
// changed.
//
// We can't just call base.onLayout() once in this case, since
// adjusting the scrollbars COULD adjust the display area, and
// thus require a new layout. The result is that when you
// affect a control's layout, we are forced to layout twice. There
// isn't any noticible flicker, but this could be a perf problem...
//
if (levent.AffectedControl != null && AutoScroll) {
base.OnLayout(levent);
}
AdjustFormScrollbars(AutoScroll);
base.OnLayout(levent);
}
///
///
///
/// Handles mouse wheel processing for our scrollbars.
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected override void OnMouseWheel(MouseEventArgs e) {
// Favor the vertical scroll bar, since it's the most
// common use. However, if there isn't a vertical
// scroll and the horizontal is on, then wheel it around.
//
if (VScroll) {
Rectangle client = ClientRectangle;
int pos = -displayRect.Y;
int maxPos = -(client.Height - displayRect.Height);
pos = Math.Max(pos - e.Delta, 0);
pos = Math.Min(pos, maxPos);
SetDisplayRectLocation(displayRect.X, -pos);
SyncScrollbars(AutoScroll);
if (e is HandledMouseEventArgs)
{
((HandledMouseEventArgs)e).Handled = true;
}
}
else if (HScroll) {
Rectangle client = ClientRectangle;
int pos = -displayRect.X;
int maxPos = -(client.Width - displayRect.Width);
pos = Math.Max(pos - e.Delta, 0);
pos = Math.Min(pos, maxPos);
SetDisplayRectLocation(-pos, displayRect.Y);
SyncScrollbars(AutoScroll);
if (e is HandledMouseEventArgs)
{
((HandledMouseEventArgs)e).Handled = true;
}
}
// The base implementation should be called before the implementation above,
// but changing the order in Whidbey would be too much of a breaking change
// for this particular class.
base.OnMouseWheel(e);
}
///
///
/// [To be supplied.]
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected override void OnRightToLeftChanged(EventArgs e) {
base.OnRightToLeftChanged(e);
resetRTLHScrollValue = true;
// When the page becomes visible, we need to call OnLayout to adjust the scrollbars.
LayoutTransaction.DoLayout(this, this, PropertyNames.RightToLeft);
}
///
protected override void OnPaintBackground (PaintEventArgs e) {
if ((HScroll || VScroll) &&
BackgroundImage != null &&
(BackgroundImageLayout == ImageLayout.Zoom || BackgroundImageLayout == ImageLayout.Stretch || BackgroundImageLayout == ImageLayout.Center)) {
if (ControlPaint.IsImageTransparent(BackgroundImage)) {
PaintTransparentBackground(e, displayRect);
}
ControlPaint.DrawBackgroundImage(e.Graphics, BackgroundImage, BackColor, BackgroundImageLayout, displayRect, displayRect, displayRect.Location);
}
else {
base.OnPaintBackground(e);
}
}
protected override void OnPaddingChanged(EventArgs e) {
// VSWhidbey 340011: DockPaddingEdges compat.
// dont call base in this instance - for App compat we should not fire Invalidate when
// the padding has changed.
EventHandler handler = (EventHandler)Events[Control.EventPaddingChanged];
if (handler != null) handler(this, e);
}
///
///
/// [To be supplied.]
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected override void OnVisibleChanged(EventArgs e) {
if (Visible) {
// When the page becomes visible, we need to call OnLayout to adjust the scrollbars.
LayoutTransaction.DoLayout(this, this, PropertyNames.Visible);
}
base.OnVisibleChanged(e);
}
// internal for Form to call
//
internal void ScaleDockPadding(float dx, float dy) {
if (dockPadding != null) {
dockPadding.Scale(dx, dy);
}
}
///
[EditorBrowsable(EditorBrowsableState.Never)]
protected override void ScaleCore(float dx, float dy) {
ScaleDockPadding(dx, dy);
base.ScaleCore(dx, dy);
}
///
///
/// Scale this form. Form overrides this to enforce a maximum / minimum size.
///
protected override void ScaleControl(SizeF factor, BoundsSpecified specified) {
ScaleDockPadding(factor.Width, factor.Height);
base.ScaleControl(factor, specified);
}
// internal for the respective scroll bars to call so that the Display Rectangle is set to
// enable the visual scroll effect.
//
internal void SetDisplayFromScrollProps(int x, int y)
{
Rectangle display = GetDisplayRectInternal();
ApplyScrollbarChanges(display);
SetDisplayRectLocation(x, y);
}
///
///
/// Adjusts the displayRect to be at the offset x, y. The contents of the
/// Form is scrolled using Windows.ScrollWindowEx.
///
//
//
protected void SetDisplayRectLocation(int x, int y) {
int xDelta = 0;
int yDelta = 0;
Rectangle client = ClientRectangle;
//VSWhidbey 141644 - The DisplayRect property modifies
// the returned rect to include padding. We don't want to
// include this padding in our adjustment of the DisplayRect
// because it interferes with the scrolling.
Rectangle displayRectangle = displayRect;
int minX = Math.Min(client.Width - displayRectangle.Width, 0);
int minY = Math.Min(client.Height - displayRectangle.Height, 0);
if (x > 0) {
x = 0;
}
if (y > 0) {
y = 0;
}
if (x < minX) {
x = minX;
}
if (y < minY) {
y = minY;
}
if (displayRectangle.X != x)
{
xDelta = x - displayRectangle.X;
}
if (displayRectangle.Y != y)
{
yDelta = y - displayRectangle.Y;
}
displayRect.X = x;
displayRect.Y = y;
if (xDelta != 0 || yDelta != 0 && IsHandleCreated) {
Rectangle cr = ClientRectangle;
NativeMethods.RECT rcClip = NativeMethods.RECT.FromXYWH(cr.X, cr.Y, cr.Width, cr.Height);
NativeMethods.RECT rcUpdate = NativeMethods.RECT.FromXYWH(cr.X, cr.Y, cr.Width, cr.Height);
SafeNativeMethods.ScrollWindowEx(new HandleRef(this, Handle), xDelta, yDelta,
null,
ref rcClip,
NativeMethods.NullHandleRef,
ref rcUpdate,
NativeMethods.SW_INVALIDATE
| NativeMethods.SW_ERASE
| NativeMethods.SW_SCROLLCHILDREN);
}
// Force child controls to update bounds.
//
for (int i=0; i
///
/// Scrolls the currently active control into view if we are an AutoScroll
/// Form that has the Horiz or Vert scrollbar displayed...
///
public void ScrollControlIntoView(Control activeControl) {
Debug.WriteLineIf(ScrollableControl.AutoScrolling.TraceVerbose, "ScrollControlIntoView(" + activeControl.GetType().FullName + ")");
Debug.Indent();
Rectangle client = ClientRectangle;
if (IsDescendant(activeControl)
&& AutoScroll
&& (HScroll || VScroll)
&& activeControl != null
&& (client.Width > 0 && client.Height > 0)) {
Debug.WriteLineIf(ScrollableControl.AutoScrolling.TraceVerbose, "Calculating...");
Point scrollLocation = ScrollToControl(activeControl);
SetScrollState(ScrollStateUserHasScrolled, false);
SetDisplayRectLocation(scrollLocation.X, scrollLocation.Y);
SyncScrollbars(true);
}
Debug.Unindent();
}
/// DCR 194760: allow containers to tweak autoscrolling. when you tab between controls contained in the scrollable control
/// this allows you to set the scroll location. This would allow you to scroll to the middle of a control, where as the default is
/// the top of the control.
///
/// Additionally there is a new AutoScrollOffset property on the child controls themselves. This lets them control where they want to
/// be scrolled to. E.g. In SelectedIndexChanged for a ListBox, you could do:
///
/// listBox1.AutoScrollOffset = parent.AutoScrollPosition;
///
///
protected virtual Point ScrollToControl(Control activeControl) {
Rectangle client = ClientRectangle;
int xCalc = displayRect.X;
int yCalc = displayRect.Y;
int xMargin = scrollMargin.Width;
int yMargin = scrollMargin.Height;
Rectangle bounds = activeControl.Bounds;
if (activeControl.ParentInternal != this) {
Debug.WriteLineIf(ScrollableControl.AutoScrolling.TraceVerbose, "not direct child, original bounds: " + bounds);
bounds = this.RectangleToClient(activeControl.ParentInternal.RectangleToScreen(bounds));
}
Debug.WriteLineIf(ScrollableControl.AutoScrolling.TraceVerbose, "adjusted bounds: " + bounds);
if (bounds.X < xMargin) {
xCalc = displayRect.X + xMargin - bounds.X;
}
else if (bounds.X + bounds.Width + xMargin > client.Width) {
xCalc = client.Width - (bounds.X + bounds.Width + xMargin - displayRect.X);
if (bounds.X + xCalc - displayRect.X < xMargin) {
xCalc = displayRect.X + xMargin - bounds.X;
}
}
if (bounds.Y < yMargin) {
yCalc = displayRect.Y + yMargin - bounds.Y;
}
else if (bounds.Y + bounds.Height + yMargin > client.Height) {
yCalc = client.Height - (bounds.Y + bounds.Height + yMargin - displayRect.Y);
if (bounds.Y + yCalc - displayRect.Y < yMargin) {
yCalc = displayRect.Y + yMargin - bounds.Y;
}
}
xCalc += activeControl.AutoScrollOffset.X;
yCalc += activeControl.AutoScrollOffset.Y;
return new Point(xCalc, yCalc);
}
private int ScrollThumbPosition(int fnBar) {
NativeMethods.SCROLLINFO si = new NativeMethods.SCROLLINFO();
si.fMask = NativeMethods.SIF_TRACKPOS;
SafeNativeMethods.GetScrollInfo(new HandleRef(this, Handle), fnBar, si);
return si.nTrackPos;
}
///
///
///
/// Occurs when the scroll box has been moved by either a mouse or keyboard action.
///
///
[SRCategory(SR.CatAction), SRDescription(SR.ScrollBarOnScrollDescr)]
public event ScrollEventHandler Scroll {
add {
Events.AddHandler(EVENT_SCROLL, value);
}
remove {
Events.RemoveHandler(EVENT_SCROLL, value);
}
}
///
///
///
/// Raises the event.
///
///
protected virtual void OnScroll(ScrollEventArgs se) {
ScrollEventHandler handler = (ScrollEventHandler)Events[EVENT_SCROLL];
if (handler != null) handler(this,se);
}
private void ResetAutoScrollMargin() {
AutoScrollMargin = Size.Empty;
}
private void ResetAutoScrollMinSize() {
AutoScrollMinSize = Size.Empty;
}
private void ResetScrollProperties(ScrollProperties scrollProperties) {
// Set only these two values as when the ScrollBars are not visible ...
// there is no meaning of the "value" property.
scrollProperties.visible = false;
scrollProperties.value = 0;
}
///
///
///
/// Sets the size
/// of the auto-scroll margins.
///
///
public void SetAutoScrollMargin(int x, int y) {
// Make sure we're not setting the margins to negative numbers
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
if (x != requestedScrollMargin.Width
|| y != requestedScrollMargin.Height) {
requestedScrollMargin = new Size(x, y);
if (AutoScroll) {
PerformLayout();
}
}
}
///
/// Actually displays or hides the horiz and vert autoscrollbars. This will
/// also adjust the values of formState to reflect the new state
///
private bool SetVisibleScrollbars(bool horiz, bool vert) {
bool needLayout = false;
if (!horiz && HScroll
|| horiz && !HScroll
|| !vert && VScroll
|| vert && !VScroll) {
needLayout = true;
}
// If we are about to show the horizontal scrollbar, then
// set this flag, so that we can set the right initial value
// based on whether we are right to left.
if (horiz && !HScroll && (RightToLeft == RightToLeft.Yes)) {
resetRTLHScrollValue = true;
}
if (needLayout) {
int x = displayRect.X;
int y = displayRect.Y;
if (!horiz) {
x = 0;
}
if (!vert) {
y = 0;
}
SetDisplayRectLocation(x, y);
SetScrollState(ScrollStateUserHasScrolled, false);
HScroll = horiz;
VScroll = vert;
//Update the visible member of ScrollBars....
if (horiz)
{
HorizontalScroll.visible = true;
}
else
{
ResetScrollProperties(HorizontalScroll);
}
if (vert)
{
VerticalScroll.visible = true;
}
else
{
ResetScrollProperties(VerticalScroll);
}
UpdateStyles();
}
return needLayout;
}
///
/// Sets the width and height of the virtual client area used in
/// autoscrolling. This will also adjust the x and y location of the
/// virtual client area if the new size forces it.
///
///
private bool SetDisplayRectangleSize(int width, int height) {
bool needLayout = false;
if (displayRect.Width != width
|| displayRect.Height != height) {
displayRect.Width = width;
displayRect.Height = height;
needLayout = true;
}
int minX = ClientRectangle.Width - width;
int minY = ClientRectangle.Height - height;
if (minX > 0) minX = 0;
if (minY > 0) minY = 0;
int x = displayRect.X;
int y = displayRect.Y;
if (!HScroll) {
x = 0;
}
if (!VScroll) {
y = 0;
}
if (x < minX) {
x = minX;
}
if (y < minY) {
y = minY;
}
SetDisplayRectLocation(x, y);
return needLayout;
}
///
///
///
/// Sets a given scroll state bit.
///
///
protected void SetScrollState(int bit, bool value) {
if (value) {
scrollState |= bit;
}
else {
scrollState &= (~bit);
}
}
///
///
/// Indicates whether the
/// property should be persisted.
///
///
private bool ShouldSerializeAutoScrollPosition() {
if (AutoScroll) {
Point pt = AutoScrollPosition;
if (pt.X != 0 || pt.Y != 0) {
return true;
}
}
return false;
}
///
///
/// Indicates whether the property should be persisted.
///
///
private bool ShouldSerializeAutoScrollMargin() {
return !AutoScrollMargin.Equals(new Size(0,0));
}
///
///
/// Indicates whether the
/// property should be persisted.
///
///
private bool ShouldSerializeAutoScrollMinSize() {
return !AutoScrollMinSize.Equals(new Size(0,0));
}
///
/// Updates the value of the autoscroll scrollbars based on the current form
/// state. This is a one-way [....], updating the scrollbars only.
///
///
private void SyncScrollbars(bool autoScroll) {
Rectangle displayRect = this.displayRect;
if (autoScroll) {
if (!IsHandleCreated) {
return;
}
if (HScroll) {
if (!HorizontalScroll.maximumSetExternally) {
HorizontalScroll.maximum = displayRect.Width-1;
}
if (!HorizontalScroll.largeChangeSetExternally) {
HorizontalScroll.largeChange = ClientRectangle.Width;
}
if (!HorizontalScroll.smallChangeSetExternally) {
HorizontalScroll.smallChange = 5;
}
if (resetRTLHScrollValue && !IsMirrored) {
resetRTLHScrollValue = false;
BeginInvoke(new EventHandler(this.OnSetScrollPosition));
}
else if(-displayRect.X >= HorizontalScroll.minimum && -displayRect.X < HorizontalScroll.maximum) {
HorizontalScroll.value = -displayRect.X;
}
HorizontalScroll.UpdateScrollInfo ();
}
if (VScroll) {
if (!VerticalScroll.maximumSetExternally) {
VerticalScroll.maximum = displayRect.Height-1;
}
if (!VerticalScroll.largeChangeSetExternally) {
VerticalScroll.largeChange = ClientRectangle.Height;
}
if (!VerticalScroll.smallChangeSetExternally) {
VerticalScroll.smallChange = 5;
}
if (-displayRect.Y >= VerticalScroll.minimum && -displayRect.Y < VerticalScroll.maximum) {
VerticalScroll.value = -displayRect.Y;
}
VerticalScroll.UpdateScrollInfo ();
}
}
else {
if (this.HorizontalScroll.Visible) {
HorizontalScroll.Value = -displayRect.X;
}
else {
ResetScrollProperties(HorizontalScroll);
}
if (this.VerticalScroll.Visible) {
VerticalScroll.Value = -displayRect.Y;
}
else {
ResetScrollProperties(VerticalScroll);
}
}
}
private void OnSetScrollPosition(object sender, EventArgs e) {
if (!IsMirrored) {
SendMessage(NativeMethods.WM_HSCROLL,
NativeMethods.Util.MAKELPARAM((RightToLeft == RightToLeft.Yes) ? NativeMethods.SB_RIGHT : NativeMethods.SB_LEFT,0), 0);
}
}
///
/// Queries the system to determine the users preference for full drag
/// of windows.
///
private void UpdateFullDrag() {
SetScrollState(ScrollStateFullDrag, SystemInformation.DragFullWindows);
}
///
/// WM_VSCROLL handler
///
///
private void WmVScroll(ref Message m) {
// The lparam is handle of the sending scrollbar, or NULL when
// the scrollbar sending the message is the "form" scrollbar...
//
if (m.LParam != IntPtr.Zero) {
base.WndProc(ref m);
return;
}
Rectangle client = ClientRectangle;
bool thumbTrack = NativeMethods.Util.LOWORD(m.WParam) != NativeMethods.SB_THUMBTRACK;
int pos = -displayRect.Y;
int oldValue = pos;
int maxPos = -(client.Height - displayRect.Height);
if (!AutoScroll) {
maxPos = this.VerticalScroll.Maximum;
}
switch (NativeMethods.Util.LOWORD(m.WParam)) {
case NativeMethods.SB_THUMBPOSITION:
case NativeMethods.SB_THUMBTRACK:
pos = ScrollThumbPosition(NativeMethods.SB_VERT);
break;
case NativeMethods.SB_LINEUP:
if (pos > 0) {
pos-=VerticalScroll.SmallChange;
}
else {
pos = 0;
}
break;
case NativeMethods.SB_LINEDOWN:
if (pos < maxPos-VerticalScroll.SmallChange) {
pos+=VerticalScroll.SmallChange;
}
else {
pos = maxPos;
}
break;
case NativeMethods.SB_PAGEUP:
if (pos > VerticalScroll.LargeChange) {
pos-=VerticalScroll.LargeChange;
}
else {
pos = 0;
}
break;
case NativeMethods.SB_PAGEDOWN:
if (pos < maxPos-VerticalScroll.LargeChange) {
pos+=VerticalScroll.LargeChange;
}
else {
pos = maxPos;
}
break;
case NativeMethods.SB_TOP:
pos = 0;
break;
case NativeMethods.SB_BOTTOM:
pos = maxPos;
break;
}
// VsW: 178279: This bugs reproes on all those machine which have SystemInformation.DragFullWindows set to false
// "thumbTrack" was incorrectly used... the usage should be identical to WnHScroll which follows.
if (GetScrollState(ScrollStateFullDrag) || thumbTrack ) {
SetScrollState(ScrollStateUserHasScrolled, true);
SetDisplayRectLocation(displayRect.X, -pos);
SyncScrollbars(AutoScroll);
}
WmOnScroll(ref m, oldValue, pos, ScrollOrientation.VerticalScroll);
}
///
/// WM_HSCROLL handler
///
///
private void WmHScroll(ref Message m) {
// The lparam is handle of the sending scrollbar, or NULL when
// the scrollbar sending the message is the "form" scrollbar...
//
if (m.LParam != IntPtr.Zero) {
base.WndProc(ref m);
return;
}
Rectangle client = ClientRectangle;
int pos = -displayRect.X;
int oldValue = pos;
int maxPos = -(client.Width - displayRect.Width);
if (!AutoScroll) {
maxPos = this.HorizontalScroll.Maximum;
}
switch (NativeMethods.Util.LOWORD(m.WParam)) {
case NativeMethods.SB_THUMBPOSITION:
case NativeMethods.SB_THUMBTRACK:
pos = ScrollThumbPosition(NativeMethods.SB_HORZ);
break;
case NativeMethods.SB_LINEUP:
if (pos > HorizontalScroll.SmallChange) {
pos-=HorizontalScroll.SmallChange;
}
else {
pos = 0;
}
break;
case NativeMethods.SB_LINEDOWN:
if (pos < maxPos-HorizontalScroll.SmallChange) {
pos+=HorizontalScroll.SmallChange;
}
else {
pos = maxPos;
}
break;
case NativeMethods.SB_PAGEUP:
if (pos > HorizontalScroll.LargeChange) {
pos-=HorizontalScroll.LargeChange;
}
else {
pos = 0;
}
break;
case NativeMethods.SB_PAGEDOWN:
if (pos < maxPos-HorizontalScroll.LargeChange) {
pos+=HorizontalScroll.LargeChange;
}
else {
pos = maxPos;
}
break;
case NativeMethods.SB_LEFT:
pos = 0;
break;
case NativeMethods.SB_RIGHT:
pos = maxPos;
break;
}
if (GetScrollState(ScrollStateFullDrag) || NativeMethods.Util.LOWORD(m.WParam) != NativeMethods.SB_THUMBTRACK) {
SetScrollState(ScrollStateUserHasScrolled, true);
SetDisplayRectLocation(-pos, displayRect.Y);
SyncScrollbars(AutoScroll);
}
WmOnScroll(ref m, oldValue, pos, ScrollOrientation.HorizontalScroll);
}
///
/// This function gets called which populates the eventArgs and fires the OnScroll( ) event passing
/// the appropriate scroll event and scroll bar.
///
///
private void WmOnScroll(ref Message m, int oldValue, int value, ScrollOrientation scrollOrientation) {
ScrollEventType type = (ScrollEventType)NativeMethods.Util.LOWORD(m.WParam);
if (type != ScrollEventType.EndScroll) {
ScrollEventArgs se = new ScrollEventArgs(type, oldValue, value, scrollOrientation);
OnScroll(se);
}
}
private void WmSettingChange(ref Message m) {
base.WndProc(ref m);
UpdateFullDrag();
}
///
///
/// The button's window procedure. Inheriting classes can override this
/// to add extra functionality, but should not forget to call
/// base.wndProc(m); to ensure the button continues to function properly.
///
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m) {
switch (m.Msg) {
case NativeMethods.WM_VSCROLL:
WmVScroll(ref m);
break;
case NativeMethods.WM_HSCROLL:
WmHScroll(ref m);
break;
case NativeMethods.WM_SETTINGCHANGE:
WmSettingChange(ref m);
break;
default:
base.WndProc(ref m);
break;
}
}
///
///
/// Determines the border padding for
/// docked controls.
///
[TypeConverterAttribute(typeof(DockPaddingEdgesConverter))]
public class DockPaddingEdges : ICloneable {
private ScrollableControl owner;
private int left;
private int right;
private int top;
private int bottom;
///
/// Creates a new DockPaddingEdges. The specified owner will
/// be notified when the values are changed.
///
internal DockPaddingEdges(ScrollableControl owner) {
this.owner = owner;
}
internal DockPaddingEdges(int left, int right, int top, int bottom) {
this.left = left;
this.right = right;
this.top = top;
this.bottom = bottom;
}
///
///
/// Gets
/// or
/// sets the padding width for all edges of a docked control.
///
[
RefreshProperties(RefreshProperties.All),
SRDescription(SR.PaddingAllDescr)
]
public int All {
get {
if (owner == null) {
if (left == right && top == bottom && left == top) {
return left;
}
else {
return 0;
}
}
else {
// The Padding struct uses -1 to indicate that LRTB are in disagreement.
// For backwards compatibility, we need to remap -1 to 0, but we need
// to be careful because it could be that they explicitly set All to -1.
if (owner.Padding.All == -1
&&
(owner.Padding.Left != -1
|| owner.Padding.Top != -1
|| owner.Padding.Right != -1
|| owner.Padding.Bottom != -1)) {
return 0;
}
return owner.Padding.All;
}
}
set {
if (owner == null) {
left = value;
top = value;
right = value;
bottom = value;
}
else {
owner.Padding = new Padding(value);
}
}
}
///
///
/// Gets
/// or
/// sets the padding width for the bottom edge of a docked control.
///
[
RefreshProperties(RefreshProperties.All),
SRDescription(SR.PaddingBottomDescr)
]
public int Bottom {
get {
if (owner == null) {
return bottom;
}
else {
return owner.Padding.Bottom;
}
}
set {
if (owner == null) {
bottom = value;
}
else {
Padding padding = owner.Padding;
padding.Bottom = value;
owner.Padding = padding;
}
}
}
///
///
/// Gets
/// or sets the padding width for the left edge of a docked control.
///
[
RefreshProperties(RefreshProperties.All),
SRDescription(SR.PaddingLeftDescr)
]
public int Left {
get {
if (owner == null) {
return left;
}
else {
return owner.Padding.Left;
}
}
set {
if (owner == null) {
left = value;
}
else {
Padding padding = owner.Padding;
padding.Left = value;
owner.Padding = padding;
}
}
}
///
///
/// Gets
/// or sets the padding width for the right edge of a docked control.
///
[
RefreshProperties(RefreshProperties.All),
SRDescription(SR.PaddingRightDescr)
]
public int Right {
get {
if (owner == null) {
return right;
}
else {
return owner.Padding.Right;
}
}
set {
if (owner == null) {
right = value;
}
else {
Padding padding = owner.Padding;
padding.Right = value;
owner.Padding = padding;
}
}
}
///
///
/// Gets
/// or sets the padding width for the top edge of a docked control.
///
[
RefreshProperties(RefreshProperties.All),
SRDescription(SR.PaddingTopDescr)
]
public int Top {
get {
if (owner == null) {
return bottom;
}
else {
return owner.Padding.Top;
}
}
set {
if (owner == null) {
top = value;
}
else {
Padding padding = owner.Padding;
padding.Top = value;
owner.Padding = padding;
}
}
}
///
///
public override bool Equals(object other) {
DockPaddingEdges dpeOther = other as DockPaddingEdges;
if (dpeOther != null) {
return this.owner.Padding.Equals(dpeOther.owner.Padding);
}
return false;
}
///
///
public override int GetHashCode() {
return base.GetHashCode();
}
///
private void ResetAll() {
All = 0;
}
///
private void ResetBottom() {
Bottom = 0;
}
///
private void ResetLeft() {
Left = 0;
}
///
private void ResetRight() {
Right = 0;
}
///
private void ResetTop() {
Top = 0;
}
internal void Scale(float dx, float dy) {
this.owner.Padding.Scale(dx, dy);
}
///
///
public override string ToString() {
return ""; // used to say "(DockPadding)" but that's useless
}
///
///
object ICloneable.Clone() {
DockPaddingEdges dpe = new DockPaddingEdges(Left, Right, Top, Bottom);
return dpe;
}
}
///
public class DockPaddingEdgesConverter : TypeConverter {
///
///
/// Retrieves the set of properties for this type. By default, a type has
/// does not return any properties. An easy implementation of this method
/// can just call TypeDescriptor.GetProperties for the correct data type.
///
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) {
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(DockPaddingEdges), attributes);
return props.Sort(new string[] {"All", "Left", "Top", "Right", "Bottom"});
}
///
///
/// Determines if this object supports properties. By default, this
/// is false.
///
public override bool GetPropertiesSupported(ITypeDescriptorContext context) {
return true;
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WebPartMovingEventArgs.cs
- LicenseManager.cs
- ResourceContainer.cs
- AdRotator.cs
- MimeMapping.cs
- SoapExtensionTypeElementCollection.cs
- XmlBoundElement.cs
- LayoutDump.cs
- Icon.cs
- ObfuscateAssemblyAttribute.cs
- EntityClientCacheEntry.cs
- MeasurementDCInfo.cs
- ToolStripItemCollection.cs
- QueryStringParameter.cs
- WebPartDisplayMode.cs
- MinMaxParagraphWidth.cs
- TemplatePartAttribute.cs
- LayoutUtils.cs
- ItemsControl.cs
- DeploymentExceptionMapper.cs
- Span.cs
- ScalarType.cs
- InvokeProviderWrapper.cs
- DataGridViewRowPostPaintEventArgs.cs
- Converter.cs
- TagPrefixAttribute.cs
- JapaneseCalendar.cs
- LateBoundBitmapDecoder.cs
- PlatformCulture.cs
- DynamicResourceExtension.cs
- ItemMap.cs
- Update.cs
- QueueException.cs
- ConfigurationPermission.cs
- PartitionerStatic.cs
- ZipPackage.cs
- SolidColorBrush.cs
- DrawListViewItemEventArgs.cs
- UseAttributeSetsAction.cs
- CacheMemory.cs
- MultiAsyncResult.cs
- DeferredRunTextReference.cs
- PolyBezierSegment.cs
- EventListenerClientSide.cs
- TransactionTraceIdentifier.cs
- PolyLineSegment.cs
- HostProtectionPermission.cs
- BigInt.cs
- InvalidateEvent.cs
- PerfCounterSection.cs
- CustomBindingCollectionElement.cs
- Ipv6Element.cs
- GenericTextProperties.cs
- validationstate.cs
- WhitespaceReader.cs
- Rect.cs
- TrackPointCollection.cs
- _SslSessionsCache.cs
- SemanticBasicElement.cs
- SchemaImporter.cs
- VisualStyleElement.cs
- RightsManagementSuppressedStream.cs
- PerformanceCounterScope.cs
- Storyboard.cs
- ValidatorUtils.cs
- BindValidationContext.cs
- ToolStripItemEventArgs.cs
- XmlSchemaType.cs
- AccessViolationException.cs
- MatrixStack.cs
- ContentPresenter.cs
- TextContainer.cs
- Script.cs
- AlignmentXValidation.cs
- BooleanStorage.cs
- StoreContentChangedEventArgs.cs
- WebPartMinimizeVerb.cs
- WebCategoryAttribute.cs
- BamlReader.cs
- EventManager.cs
- MemberDescriptor.cs
- CaseCqlBlock.cs
- BaseParaClient.cs
- CoTaskMemHandle.cs
- BitmapSource.cs
- BindingMAnagerBase.cs
- AppSettingsExpressionEditor.cs
- NavigationWindow.cs
- GlyphShapingProperties.cs
- ListSortDescription.cs
- HttpListenerElement.cs
- KeyedHashAlgorithm.cs
- _SSPISessionCache.cs
- DataRow.cs
- NetSectionGroup.cs
- SqlClientFactory.cs
- ResponseStream.cs
- WebBrowsableAttribute.cs
- XmlAttributeOverrides.cs
- BackgroundWorker.cs