Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / WinForms / Managed / System / WinForms / ScrollableControl.cs / 1305376 / 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; ////// /// [ 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 ////// Defines a base class for controls that support auto-scrolling behavior. /// ////// 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; /// /// /// public ScrollableControl() : base() { SetStyle(ControlStyles.ContainerControl, true); SetStyle(ControlStyles.AllPaintingInWmPaint, false); SetScrollState(ScrollStateAutoScrolling, false); } ////// Initializes a new instance of the ///class. /// /// /// [ 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 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), 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 size of the auto-scroll /// margin. /// ////// /// [ 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 location of the auto-scroll position. ////// /// [ SRCategory(SR.CatLayout), Localizable(true), SRDescription(SR.FormAutoScrollMinSizeDescr) ] public Size AutoScrollMinSize { get { return userAutoScrollMinSize; } set { if (value != userAutoScrollMinSize) { userAutoScrollMinSize = value; AutoScroll = true; PerformLayout(); } } } ///Gets or sets the mimimum size of the auto-scroll. ////// /// /// 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; } } ////// Retrieves the CreateParams used to create the window. /// If a subclass overrides this function, it must call the base implementation. /// ////// /// /// 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); } } ////// 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. /// ////// 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; } } /// /// /// protected bool HScroll { get { return GetScrollState(ScrollStateHScrollVisible); } set { SetScrollState(ScrollStateHScrollVisible, value); } } ////// Gets or /// sets a value indicating whether the horizontal scroll bar is visible. /// ////// /// [ 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 the Horizontal Scroll bar for this ScrollableControl. ////// /// protected bool VScroll { get { return GetScrollState(ScrollStateVScrollVisible); } set { SetScrollState(ScrollStateVScrollVisible, value); } } ////// Gets or /// sets a value indicating whether the vertical scroll bar is visible. /// ////// /// [ 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 Veritcal Scroll bar for this ScrollableControl. ////// /// [ DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false), EditorBrowsable(EditorBrowsableState.Never) ] public DockPaddingEdges DockPadding { get { if (dockPadding == null) { dockPadding = new DockPaddingEdges(this); } return dockPadding; } } ///Gets the dock padding settings for all /// edges of the control. ////// /// [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/// Adjusts /// the auto-scroll bars on the container based on the current control /// positions and the control currently selected. /// ///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; } /// /// /// [EditorBrowsable(EditorBrowsableState.Advanced)] protected bool GetScrollState(int bit) { return(bit & scrollState) == bit; } ////// Tests a given scroll state bit to determine if it is set. /// ////// /// /// 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); } ////// /// [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); } ///[To be supplied.] ///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); } /// /// /// [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); } } ///[To be supplied.] ///[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; } ////// /// [SRCategory(SR.CatAction), SRDescription(SR.ScrollBarOnScrollDescr)] public event ScrollEventHandler Scroll { add { Events.AddHandler(EVENT_SCROLL, value); } remove { Events.RemoveHandler(EVENT_SCROLL, value); } } ////// Occurs when the scroll box has been moved by either a mouse or keyboard action. /// ////// /// 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; } ////// Raises the ///event. /// /// /// 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(); } } } ////// Sets the size /// of the auto-scroll margins. /// ////// 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; } /// /// /// protected void SetScrollState(int bit, bool value) { if (value) { scrollState |= bit; } else { scrollState &= (~bit); } } ////// Sets a given scroll state bit. /// ////// 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)); } ////// Indicates whether the ////// property should be persisted. /// /// 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; } } /// /// /// [TypeConverterAttribute(typeof(DockPaddingEdgesConverter))] public class DockPaddingEdges : ICloneable { private ScrollableControl owner; private int left; private int right; private int top; private int bottom; ///Determines the border padding for /// docked controls. ////// 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; } ////// /// [ 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 all edges 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 bottom 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 left 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 right 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; } } } ///Gets /// or sets the padding width for the top edge of a docked control. ////// 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; ////// /// [ 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 ////// Defines a base class for controls that support auto-scrolling behavior. /// ////// 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; /// /// /// public ScrollableControl() : base() { SetStyle(ControlStyles.ContainerControl, true); SetStyle(ControlStyles.AllPaintingInWmPaint, false); SetScrollState(ScrollStateAutoScrolling, false); } ////// Initializes a new instance of the ///class. /// /// /// [ 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 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), 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 size of the auto-scroll /// margin. /// ////// /// [ 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 location of the auto-scroll position. ////// /// [ SRCategory(SR.CatLayout), Localizable(true), SRDescription(SR.FormAutoScrollMinSizeDescr) ] public Size AutoScrollMinSize { get { return userAutoScrollMinSize; } set { if (value != userAutoScrollMinSize) { userAutoScrollMinSize = value; AutoScroll = true; PerformLayout(); } } } ///Gets or sets the mimimum size of the auto-scroll. ////// /// /// 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; } } ////// Retrieves the CreateParams used to create the window. /// If a subclass overrides this function, it must call the base implementation. /// ////// /// /// 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); } } ////// 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. /// ////// 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; } } /// /// /// protected bool HScroll { get { return GetScrollState(ScrollStateHScrollVisible); } set { SetScrollState(ScrollStateHScrollVisible, value); } } ////// Gets or /// sets a value indicating whether the horizontal scroll bar is visible. /// ////// /// [ 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 the Horizontal Scroll bar for this ScrollableControl. ////// /// protected bool VScroll { get { return GetScrollState(ScrollStateVScrollVisible); } set { SetScrollState(ScrollStateVScrollVisible, value); } } ////// Gets or /// sets a value indicating whether the vertical scroll bar is visible. /// ////// /// [ 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 Veritcal Scroll bar for this ScrollableControl. ////// /// [ DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false), EditorBrowsable(EditorBrowsableState.Never) ] public DockPaddingEdges DockPadding { get { if (dockPadding == null) { dockPadding = new DockPaddingEdges(this); } return dockPadding; } } ///Gets the dock padding settings for all /// edges of the control. ////// /// [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/// Adjusts /// the auto-scroll bars on the container based on the current control /// positions and the control currently selected. /// ///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; } /// /// /// [EditorBrowsable(EditorBrowsableState.Advanced)] protected bool GetScrollState(int bit) { return(bit & scrollState) == bit; } ////// Tests a given scroll state bit to determine if it is set. /// ////// /// /// 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); } ////// /// [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); } ///[To be supplied.] ///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); } /// /// /// [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); } } ///[To be supplied.] ///[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; } ////// /// [SRCategory(SR.CatAction), SRDescription(SR.ScrollBarOnScrollDescr)] public event ScrollEventHandler Scroll { add { Events.AddHandler(EVENT_SCROLL, value); } remove { Events.RemoveHandler(EVENT_SCROLL, value); } } ////// Occurs when the scroll box has been moved by either a mouse or keyboard action. /// ////// /// 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; } ////// Raises the ///event. /// /// /// 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(); } } } ////// Sets the size /// of the auto-scroll margins. /// ////// 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; } /// /// /// protected void SetScrollState(int bit, bool value) { if (value) { scrollState |= bit; } else { scrollState &= (~bit); } } ////// Sets a given scroll state bit. /// ////// 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)); } ////// Indicates whether the ////// property should be persisted. /// /// 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; } } /// /// /// [TypeConverterAttribute(typeof(DockPaddingEdgesConverter))] public class DockPaddingEdges : ICloneable { private ScrollableControl owner; private int left; private int right; private int top; private int bottom; ///Determines the border padding for /// docked controls. ////// 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; } ////// /// [ 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 all edges 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 bottom 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 left 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 right 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; } } } ///Gets /// or sets the padding width for the top edge of a docked control. ////// 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
- BookmarkResumptionRecord.cs
- ConstructorBuilder.cs
- SqlVisitor.cs
- DeferrableContentConverter.cs
- DataGridViewLinkCell.cs
- PolicyLevel.cs
- Stacktrace.cs
- PersistenceTypeAttribute.cs
- AmbientValueAttribute.cs
- embossbitmapeffect.cs
- UIElement.cs
- BitmapEffectInput.cs
- _AcceptOverlappedAsyncResult.cs
- Config.cs
- HostExecutionContextManager.cs
- BamlVersionHeader.cs
- ReadOnlyDataSourceView.cs
- MouseActionConverter.cs
- UnsafeNativeMethods.cs
- AppDomainInfo.cs
- PointHitTestParameters.cs
- VoiceChangeEventArgs.cs
- InboundActivityHelper.cs
- DataGridViewCellStyleEditor.cs
- TriggerBase.cs
- CharStorage.cs
- HandlerBase.cs
- ObjectDisposedException.cs
- TraceUtility.cs
- ArrayWithOffset.cs
- UIElementCollection.cs
- AttributeCollection.cs
- EventWaitHandle.cs
- Filter.cs
- SQLSingle.cs
- ThemeDictionaryExtension.cs
- ContainerUtilities.cs
- DispatchWrapper.cs
- TextTreeInsertElementUndoUnit.cs
- TrackingStringDictionary.cs
- XmlSignatureManifest.cs
- Rotation3DAnimationBase.cs
- PageBreakRecord.cs
- FloatUtil.cs
- ProgressBarBrushConverter.cs
- BitmapMetadataBlob.cs
- InProcStateClientManager.cs
- InfoCardXmlSerializer.cs
- DataSourceControlBuilder.cs
- TextRange.cs
- Literal.cs
- IQueryable.cs
- UserPreferenceChangingEventArgs.cs
- ChangePasswordAutoFormat.cs
- ServiceBehaviorAttribute.cs
- TableHeaderCell.cs
- CookieParameter.cs
- RelationshipNavigation.cs
- URLAttribute.cs
- BindingExpressionBase.cs
- StyleSheetComponentEditor.cs
- ArglessEventHandlerProxy.cs
- MembershipUser.cs
- Translator.cs
- XmlExceptionHelper.cs
- ReachDocumentReferenceCollectionSerializer.cs
- DesignTableCollection.cs
- PageParserFilter.cs
- RenderingEventArgs.cs
- AsyncResult.cs
- Types.cs
- CodeBlockBuilder.cs
- XmlSchemaComplexContentExtension.cs
- RangeContentEnumerator.cs
- HtmlFormParameterWriter.cs
- XmlReader.cs
- EtwTrackingBehavior.cs
- DragDeltaEventArgs.cs
- AsyncResult.cs
- SeverityFilter.cs
- ViewRendering.cs
- BrowsableAttribute.cs
- ContentControl.cs
- XmlCodeExporter.cs
- BaseTreeIterator.cs
- CodeDesigner.cs
- _RequestCacheProtocol.cs
- GroupDescription.cs
- EventHandlerList.cs
- XmlNodeChangedEventArgs.cs
- InstanceLockLostException.cs
- SystemGatewayIPAddressInformation.cs
- HotSpot.cs
- querybuilder.cs
- AssemblyFilter.cs
- DbConnectionFactory.cs
- IndexedEnumerable.cs
- StylusPointProperties.cs
- EntityModelBuildProvider.cs
- StandardToolWindows.cs