Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Controls / Primitives / ScrollContentPresenter.cs / 2 / ScrollContentPresenter.cs
//----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// File: ScrollContentPresenter.cs
//
// Description: Contains the ScrollContentPresenter class.
//
// History:
// 12/08/2003 : greglett - Created in WCP_break branch
//
//---------------------------------------------------------------------------
using MS.Internal;
using MS.Utility;
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Threading;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Automation.Provider;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Markup;
namespace System.Windows.Controls
{
///
///
sealed public class ScrollContentPresenter : ContentPresenter, IScrollInfo
{
//-------------------------------------------------------------------
//
// Constructors
//
//-------------------------------------------------------------------
#region Constructors
///
/// Default DependencyObject constructor
///
///
/// Automatic determination of current Dispatcher. Use alternative constructor
/// that accepts a Dispatcher for best performance.
///
public ScrollContentPresenter() : base()
{
_adornerLayer = new AdornerLayer();
}
#endregion
//--------------------------------------------------------------------
//
// Public Methods
//
//-------------------------------------------------------------------
#region Public Methods
///
/// Scroll content by one line to the top.
///
public void LineUp()
{
if (IsScrollClient) { SetVerticalOffset(VerticalOffset - ScrollViewer._scrollLineDelta); }
}
///
/// Scroll content by one line to the bottom.
///
public void LineDown()
{
if (IsScrollClient) { SetVerticalOffset(VerticalOffset + ScrollViewer._scrollLineDelta); }
}
///
/// Scroll content by one line to the left.
///
public void LineLeft()
{
if (IsScrollClient) { SetHorizontalOffset(HorizontalOffset - ScrollViewer._scrollLineDelta); }
}
///
/// Scroll content by one line to the right.
///
public void LineRight()
{
if (IsScrollClient) { SetHorizontalOffset(HorizontalOffset + ScrollViewer._scrollLineDelta); }
}
///
/// Scroll content by one page to the top.
///
public void PageUp()
{
if (IsScrollClient) { SetVerticalOffset(VerticalOffset - ViewportHeight); }
}
///
/// Scroll content by one page to the bottom.
///
public void PageDown()
{
if (IsScrollClient) { SetVerticalOffset(VerticalOffset + ViewportHeight); }
}
///
/// Scroll content by one page to the left.
///
public void PageLeft()
{
if (IsScrollClient) { SetHorizontalOffset(HorizontalOffset - ViewportWidth); }
}
///
/// Scroll content by one page to the right.
///
public void PageRight()
{
if (IsScrollClient) { SetHorizontalOffset(HorizontalOffset + ViewportWidth); }
}
///
/// Scroll content by one line to the top.
///
public void MouseWheelUp()
{
if (IsScrollClient) { SetVerticalOffset(VerticalOffset - ScrollViewer._mouseWheelDelta); }
}
///
/// Scroll content by one line to the bottom.
///
public void MouseWheelDown()
{
if (IsScrollClient) { SetVerticalOffset(VerticalOffset + ScrollViewer._mouseWheelDelta); }
}
///
/// Scroll content by one page to the top.
///
public void MouseWheelLeft()
{
if (IsScrollClient) { SetHorizontalOffset(HorizontalOffset - ScrollViewer._mouseWheelDelta); }
}
///
/// Scroll content by one page to the bottom.
///
public void MouseWheelRight()
{
if (IsScrollClient) { SetHorizontalOffset(HorizontalOffset + ScrollViewer._mouseWheelDelta); }
}
///
/// Set the HorizontalOffset to the passed value.
///
public void SetHorizontalOffset(double offset)
{
if (IsScrollClient)
{
double newValue = ValidateInputOffset(offset, "HorizontalOffset");
if (!DoubleUtil.AreClose(EnsureScrollData()._offset.X, newValue))
{
_scrollData._offset.X = newValue;
InvalidateArrange();
}
}
}
///
/// Set the VerticalOffset to the passed value.
///
public void SetVerticalOffset(double offset)
{
if (IsScrollClient)
{
double newValue = ValidateInputOffset(offset, "VerticalOffset");
if (!DoubleUtil.AreClose(EnsureScrollData()._offset.Y, newValue))
{
_scrollData._offset.Y = newValue;
InvalidateArrange();
}
}
}
///
/// ScrollContentPresenter implementation of .
///
public Rect MakeVisible(Visual visual, Rect rectangle)
{
return MakeVisible(visual, rectangle, true);
}
#endregion
//--------------------------------------------------------------------
//
// Public Properties (CLR + Avalon)
//
//--------------------------------------------------------------------
#region Public Properties
///
/// AdornerLayer on which adorners are rendered.
/// Adorners are rendered under the ScrollContentPresenter's clip region.
///
public AdornerLayer AdornerLayer
{
get { return _adornerLayer; }
}
///
/// This property indicates whether the ScrollContentPresenter should try to allow the Content
/// to scroll or not. A true value indicates Content should be allowed to scroll if it supports
/// IScrollInfo. A false value will cause ScrollContentPresenter to always act as the scrolling
/// client.
///
public bool CanContentScroll
{
get { return (bool) GetValue(CanContentScrollProperty); }
set { SetValue(CanContentScrollProperty, value); }
}
///
/// ScrollContentPresenter reacts to this property by changing it's child measurement algorithm.
/// If scrolling in a dimension, infinite space is allowed the child; otherwise, available size is preserved.
///
public bool CanHorizontallyScroll
{
get { return (IsScrollClient) ? EnsureScrollData()._canHorizontallyScroll : false; }
set
{
if (IsScrollClient && (EnsureScrollData()._canHorizontallyScroll != value))
{
_scrollData._canHorizontallyScroll = value;
InvalidateMeasure();
}
}
}
///
/// ScrollContentPresenter reacts to this property by changing it's child measurement algorithm.
/// If scrolling in a dimension, infinite space is allowed the child; otherwise, available size is preserved.
///
public bool CanVerticallyScroll
{
get { return (IsScrollClient) ? EnsureScrollData()._canVerticallyScroll : false; }
set
{
if (IsScrollClient && (EnsureScrollData()._canVerticallyScroll != value))
{
_scrollData._canVerticallyScroll = value;
InvalidateMeasure();
}
}
}
///
/// ExtentWidth contains the horizontal size of the scrolled content element in 1/96"
///
public double ExtentWidth
{
get { return (IsScrollClient) ? EnsureScrollData()._extent.Width : 0.0; }
}
///
/// ExtentHeight contains the vertical size of the scrolled content element in 1/96"
///
public double ExtentHeight
{
get { return (IsScrollClient) ? EnsureScrollData()._extent.Height : 0.0; }
}
///
/// ViewportWidth contains the horizontal size of content's visible range in 1/96"
///
public double ViewportWidth
{
get { return (IsScrollClient) ? EnsureScrollData()._viewport.Width : 0.0; }
}
///
/// ViewportHeight contains the vertical size of content's visible range in 1/96"
///
public double ViewportHeight
{
get { return (IsScrollClient) ? EnsureScrollData()._viewport.Height : 0.0; }
}
///
/// HorizontalOffset is the horizontal offset of the scrolled content in 1/96".
///
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public double HorizontalOffset
{
get { return (IsScrollClient) ? EnsureScrollData()._computedOffset.X : 0.0; }
}
///
/// VerticalOffset is the vertical offset of the scrolled content in 1/96".
///
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public double VerticalOffset
{
get { return (IsScrollClient) ? EnsureScrollData()._computedOffset.Y : 0.0; }
}
///
/// ScrollOwner is the container that controls any scrollbars, headers, etc... that are dependant
/// on this ScrollArea's properties.
///
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ScrollViewer ScrollOwner
{
get { return (IsScrollClient) ? _scrollData._scrollOwner: null; }
set { if (IsScrollClient) { _scrollData._scrollOwner = value; } }
}
///
/// DependencyProperty for property.
///
public static readonly DependencyProperty CanContentScrollProperty =
ScrollViewer.CanContentScrollProperty.AddOwner(
typeof(ScrollContentPresenter),
new FrameworkPropertyMetadata(new PropertyChangedCallback(OnCanContentScrollChanged)));
#endregion
//-------------------------------------------------------------------
//
// Protected Methods
//
//--------------------------------------------------------------------
#region Protected Methods
///
/// Returns the Visual children count.
///
protected override int VisualChildrenCount
{
get
{
// Four states make sense:
// 0 Children. No Content or AdornerLayer. Valid - do nothing.
// 2 Children. Content is first child, AdornerLayer
// One for the base.TemplateChild and one for the _adornerlayer.
return (base.TemplateChild == null) ? 0 : 2;
}
}
///
/// Returns the child at the specified index.
///
protected override Visual GetVisualChild(int index)
{
//check if there is a TemplateChild on FrameworkElement
if (base.TemplateChild == null)
{
throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange));
}
else
{
switch (index)
{
case 0:
return base.TemplateChild;
case 1:
return _adornerLayer;
default:
throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange));
}
}
}
///
/// Gets or sets the template child of the FrameworkElement.
///
override internal UIElement TemplateChild
{
get
{
return base.TemplateChild;
}
set
{
UIElement oldTemplate = base.TemplateChild;
if (value != oldTemplate)
{
if (oldTemplate != null && value == null)
{
// If we used to have a template child and we don't have a
// new template child disconnect the adorner layer.
this.RemoveVisualChild(_adornerLayer);
}
base.TemplateChild = value;
if(oldTemplate == null && value != null)
{
// If we did not use to have a template child, but we have one
// now, attach the adorner layer.
this.AddVisualChild(_adornerLayer);
}
}
}
}
///
///
protected override Size MeasureOverride(Size constraint)
{
Size desiredSize = new Size();
int count = this.VisualChildrenCount;
bool etwTracingEnabled = IsScrollClient && EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal);
if (etwTracingEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), MS.Utility.EventType.StartEvent, "SCROLLCONTENTPRESENTER:MeasureOverride");
}
if (count > 0)
{
// The AdornerLayer is always the size of our surface, and does not contribute to our own size.
_adornerLayer.Measure(constraint);
if(!IsScrollClient)
{
desiredSize = base.MeasureOverride(constraint);
}
else
{
Size childConstraint = constraint;
if (_scrollData._canHorizontallyScroll) { childConstraint.Width = Double.PositiveInfinity; }
if (_scrollData._canVerticallyScroll) { childConstraint.Height = Double.PositiveInfinity; }
desiredSize = base.MeasureOverride(childConstraint);
}
}
// If we're handling scrolling (as the physical scrolling client, validate properties.
if (IsScrollClient)
{
VerifyScrollData(constraint, desiredSize);
}
desiredSize.Width = Math.Min(constraint.Width, desiredSize.Width);
desiredSize.Height = Math.Min(constraint.Height, desiredSize.Height);
if (etwTracingEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), MS.Utility.EventType.EndEvent, "SCROLLCONTENTPRESENTER:MeasureOverride");
}
return desiredSize;
}
///
///
protected override Size ArrangeOverride(Size arrangeSize)
{
int count = this.VisualChildrenCount;
bool etwTracingEnabled = IsScrollClient && EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal);
if (etwTracingEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), MS.Utility.EventType.StartEvent, "SCROLLCONTENTPRESENTER:ArrangeOverride");
}
// Verifies IScrollInfo properties & invalidates ScrollViewer if necessary.
if (IsScrollClient)
{
VerifyScrollData(arrangeSize, _scrollData._extent);
}
if (count>0)
{
_adornerLayer.Arrange(new Rect(arrangeSize));
UIElement child = this.GetVisualChild(0) as UIElement;
if (child != null)
{
Rect childRect = new Rect(child.DesiredSize);
if (IsScrollClient)
{
childRect.X = -HorizontalOffset;
childRect.Y = -VerticalOffset;
}
//this is needed to stretch the child to arrange space,
childRect.Width = Math.Max(childRect.Width, arrangeSize.Width);
childRect.Height = Math.Max(childRect.Height, arrangeSize.Height);
child.Arrange(childRect);
}
}
if (etwTracingEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), MS.Utility.EventType.EndEvent, "SCROLLCONTENTPRESENTER:ArrangeOverride");
}
return (arrangeSize);
}
///
/// Override of .
///
/// Viewport geometry
protected override Geometry GetLayoutClip(Size layoutSlotSize)
{
return new RectangleGeometry(new Rect(RenderSize));
}
///
/// Called when the Template's tree has been generated
///
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
// Add the AdornerLayer to our visual tree.
// Iff we have content, we need an adorner layer.
// It has Content(eg. Button, TextBlock) as its first child and AdornerLayer as its second child
// Get our scrolling owner and content talking.
HookupScrollingComponents();
}
#endregion
//-------------------------------------------------------------------
//
// Internal Methods
//
//-------------------------------------------------------------------
#region Internal Methods
///
/// ScrollContentPresenter implementation of .
///
/// The Visual that should become visible
/// A rectangle representing in the visual's coordinate space to make visible.
/// If true the method throws an exception when an error is encountered, otherwise the method returns Rect.Empty when an error is encountered
///
/// A rectangle in the IScrollInfo's coordinate space that has been made visible.
/// Other ancestors to in turn make this new rectangle visible.
/// The rectangle should generally be a transformed version of the input rectangle. In some cases, like
/// when the input rectangle cannot entirely fit in the viewport, the return value might be smaller.
///
internal Rect MakeVisible(Visual visual, Rect rectangle, bool throwOnError)
{
//
//
// Note: This code presently assumes we/children are layout clean. See work item 22269 for more detail.
//
// We can only work on visuals that are us or children.
// An empty rect has no size or position. We can't meaningfully use it.
if (rectangle.IsEmpty
|| visual == null
|| visual == (Visual)this
|| !this.IsAncestorOf(visual))
{
return Rect.Empty;
}
// This is a false positive by PreSharp. visual cannot be null because of the 'if' check above
#pragma warning disable 1634, 1691
#pragma warning disable 56506
// Compute the child's rect relative to (0,0) in our coordinate space.
GeneralTransform childTransform = visual.TransformToAncestor(this);
#pragma warning restore 56506
#pragma warning restore 1634, 1691
rectangle = childTransform.TransformBounds(rectangle);
if (!IsScrollClient)
{
return rectangle;
}
// Initialize the viewport
Rect viewport = new Rect(HorizontalOffset, VerticalOffset, ViewportWidth, ViewportHeight);
rectangle.X += viewport.X;
rectangle.Y += viewport.Y;
// Compute the offsets required to minimally scroll the child maximally into view.
double minX = ComputeScrollOffsetWithMinimalScroll(viewport.Left, viewport.Right, rectangle.Left, rectangle.Right);
double minY = ComputeScrollOffsetWithMinimalScroll(viewport.Top, viewport.Bottom, rectangle.Top, rectangle.Bottom);
// We have computed the scrolling offsets; scroll to them.
SetHorizontalOffset(minX);
SetVerticalOffset(minY);
// Compute the visible rectangle of the child relative to the viewport.
viewport.X = minX;
viewport.Y = minY;
rectangle.Intersect(viewport);
if (throwOnError)
{
//
rectangle.X -= viewport.X;
rectangle.Y -= viewport.Y;
}
else
{
//
if (!rectangle.IsEmpty)
{
rectangle.X -= viewport.X;
rectangle.Y -= viewport.Y;
}
}
// Return the rectangle
return rectangle;
}
internal static double ComputeScrollOffsetWithMinimalScroll(
double topView,
double bottomView,
double topChild,
double bottomChild)
{
// # CHILD POSITION CHILD SIZE SCROLL REMEDY
// 1 Above viewport <= viewport Down Align top edge of child & viewport
// 2 Above viewport > viewport Down Align bottom edge of child & viewport
// 3 Below viewport <= viewport Up Align bottom edge of child & viewport
// 4 Below viewport > viewport Up Align top edge of child & viewport
// 5 Entirely within viewport NA No scroll.
// 6 Spanning viewport NA No scroll.
//
// Note: "Above viewport" = childTop above viewportTop, childBottom above viewportBottom
// "Below viewport" = childTop below viewportTop, childBottom below viewportBottom
// These child thus may overlap with the viewport, but will scroll the same direction/
bool fAbove = DoubleUtil.LessThan(topChild, topView) && DoubleUtil.LessThan(bottomChild, bottomView);
bool fBelow = DoubleUtil.GreaterThan(bottomChild, bottomView) && DoubleUtil.GreaterThan(topChild, topView);
bool fLarger = (bottomChild - topChild) > (bottomView - topView);
// Handle Cases: 1 & 4 above
if ((fAbove && !fLarger)
|| (fBelow && fLarger))
{
return topChild;
}
// Handle Cases: 2 & 3 above
else if (fAbove || fBelow)
{
return (bottomChild - (bottomView - topView));
}
// Handle cases: 5 & 6 above.
return topView;
}
static internal double ValidateInputOffset(double offset, string parameterName)
{
if (DoubleUtil.IsNaN(offset))
{
throw new ArgumentOutOfRangeException(parameterName, SR.Get(SRID.ScrollViewer_CannotBeNaN, parameterName));
}
return Math.Max(0.0, offset);
}
#endregion
//-------------------------------------------------------------------
//
// Private Methods
//
//--------------------------------------------------------------------
#region Private Methods
private ScrollData EnsureScrollData()
{
if (_scrollData == null) { _scrollData = new ScrollData(); }
return _scrollData;
}
// Helper method to get our ScrollViewer owner and its scrolling content talking.
// Method introduces the current owner/content, and clears a from any previous content.
internal void HookupScrollingComponents()
{
// We need to introduce our IScrollInfo to our ScrollViewer (and break any previous links).
ScrollViewer scrollContainer = TemplatedParent as ScrollViewer;
// If our content is not an IScrollInfo, we should have selected a style that contains one.
// This (readonly) style contains an AdornerDecorator with a ScrollArea child.
if (scrollContainer != null)
{
IScrollInfo si = null;
if (CanContentScroll)
{
// We need to get an IScrollInfo to introduce to the ScrollViewer.
// 1. Try our content...
si = Content as IScrollInfo;
// 2. Our child might be an ItemsPresenter. In this case check its child for being an IScrollInfo
if (si == null)
{
ItemsPresenter itemsPresenter = Content as ItemsPresenter;
if (itemsPresenter != null)
{
itemsPresenter.ApplyTemplate();
int count = VisualTreeHelper.GetChildrenCount(itemsPresenter);
if(count > 0)
si = VisualTreeHelper.GetChild(itemsPresenter, 0) as IScrollInfo;
}
}
}
// 3. As a final fallback, we use ourself.
if (si == null)
{
si = (IScrollInfo)this;
EnsureScrollData();
}
// Detach any differing previous IScrollInfo from ScrollViewer
if (si != _scrollInfo && _scrollInfo != null)
{
if (IsScrollClient) { _scrollData = null; }
else _scrollInfo.ScrollOwner = null;
}
// Introduce our ScrollViewer and IScrollInfo to each other.
if (si != null)
{
_scrollInfo = si; // At this point, we pass IsScrollClient if si == this.
si.ScrollOwner = scrollContainer;
scrollContainer.ScrollInfo = si;
}
}
// We're not really in a valid scrolling scenario. Break any previous references, and get us
// back into a totally unlinked state.
else if (_scrollInfo != null)
{
if (_scrollInfo.ScrollOwner != null) { _scrollInfo.ScrollOwner.ScrollInfo = null; }
_scrollInfo.ScrollOwner = null;
_scrollInfo = null;
_scrollData = null;
}
}
// Verifies scrolling data using the passed viewport and extent as newly computed values.
// Checks the X/Y offset and coerces them into the range [0, Extent - ViewportSize]
// If extent, viewport, or the newly coerced offsets are different than the existing offset,
// cachces are updated and InvalidateScrollInfo() is called.
private void VerifyScrollData(Size viewport, Size extent)
{
Debug.Assert(IsScrollClient);
bool fValid = true;
// These two lines of code are questionable, but they are needed right now as VSB may return
// Infinity size from measure, which is a regression from the old scrolling model.
// They also have the incidental affect of probably avoiding reinvalidation at Arrange
// when inside a parent that measures you to Infinity.
if (Double.IsInfinity(viewport.Width)) viewport.Width = extent.Width;
if (Double.IsInfinity(viewport.Height)) viewport.Height = extent.Height;
fValid &= DoubleUtil.AreClose(viewport, _scrollData._viewport);
fValid &= DoubleUtil.AreClose(extent, _scrollData._extent);
_scrollData._viewport = viewport;
_scrollData._extent = extent;
fValid &= CoerceOffsets();
if (!fValid)
{
ScrollOwner.InvalidateScrollInfo();
}
}
// Returns an offset coerced into the [0, Extent - Viewport] range.
// Internal because it is also used by other Avalon ISI implementations (just to avoid code duplication).
static internal double CoerceOffset(double offset, double extent, double viewport)
{
if (offset > extent - viewport) { offset = extent - viewport; }
if (offset < 0) { offset = 0; }
return offset;
}
private bool CoerceOffsets()
{
Debug.Assert(IsScrollClient);
Vector computedOffset = new Vector(
CoerceOffset(_scrollData._offset.X, _scrollData._extent.Width, _scrollData._viewport.Width),
CoerceOffset(_scrollData._offset.Y, _scrollData._extent.Height, _scrollData._viewport.Height));
bool fValid = DoubleUtil.AreClose(_scrollData._computedOffset, computedOffset);
_scrollData._computedOffset = computedOffset;
return fValid;
}
// This property is structurally important; we can't do layout without it set right.
// So, we synchronously make changes.
static private void OnCanContentScrollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ScrollContentPresenter scp = (ScrollContentPresenter)d;
if (scp._scrollInfo == null)
{
return;
}
//
scp.HookupScrollingComponents();
scp.InvalidateMeasure();
}
#endregion
//-------------------------------------------------------------------
//
// Private Properties
//
//--------------------------------------------------------------------
#region Private Properties
private bool IsScrollClient
{
get { return (_scrollInfo == this); }
}
//
// This property
// 1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject
// 2. This is a performance optimization
//
internal override int EffectiveValuesInitialSize
{
get { return 42; }
}
#endregion
//--------------------------------------------------------------------
//
// Private Fields
//
//-------------------------------------------------------------------
#region Private Fields
// Only one of the following will be used.
// The _scrollInfo holds a content IScrollInfo implementation that is given to the ScrollViewer.
// _scrollData holds values for the scrolling properties we use if we are handling IScrollInfo for the ScrollViewer ourself.
// ScrollData could implement IScrollInfo, but then the v-table would hurt in the common case as much as we save
// in the less common case.
private IScrollInfo _scrollInfo;
private ScrollData _scrollData;
// To hold adorners (caret, &c...) under the clipping region of the scroller.
private readonly AdornerLayer _adornerLayer;
#endregion
//------------------------------------------------------
//
// Private Structures / Classes
//
//-----------------------------------------------------
#region Private Structures Classes
//-----------------------------------------------------------
// ScrollData class
//-----------------------------------------------------------
#region ScrollData
// Helper class to hold scrolling data.
// This class exists to reduce working set when SCP is delegating to another implementation of ISI.
// Standard "extra pointer always for less data sometimes" cache savings model:
//
private class ScrollData
{
internal ScrollViewer _scrollOwner;
internal bool _canHorizontallyScroll;
internal bool _canVerticallyScroll;
internal Vector _offset; // Set scroll offset of content. Positive corresponds to a visually upward offset.
internal Vector _computedOffset; // Actual (computed) scroll offset of content. "" ""
internal Size _viewport; // ViewportSize is computed from our FinalSize, but may be in different units.
internal Size _extent; // Extent is the total size of our content.
}
#endregion ScrollData
#endregion Private Structures Classes
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// File: ScrollContentPresenter.cs
//
// Description: Contains the ScrollContentPresenter class.
//
// History:
// 12/08/2003 : greglett - Created in WCP_break branch
//
//---------------------------------------------------------------------------
using MS.Internal;
using MS.Utility;
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Threading;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Automation.Provider;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Markup;
namespace System.Windows.Controls
{
///
///
sealed public class ScrollContentPresenter : ContentPresenter, IScrollInfo
{
//-------------------------------------------------------------------
//
// Constructors
//
//-------------------------------------------------------------------
#region Constructors
///
/// Default DependencyObject constructor
///
///
/// Automatic determination of current Dispatcher. Use alternative constructor
/// that accepts a Dispatcher for best performance.
///
public ScrollContentPresenter() : base()
{
_adornerLayer = new AdornerLayer();
}
#endregion
//--------------------------------------------------------------------
//
// Public Methods
//
//-------------------------------------------------------------------
#region Public Methods
///
/// Scroll content by one line to the top.
///
public void LineUp()
{
if (IsScrollClient) { SetVerticalOffset(VerticalOffset - ScrollViewer._scrollLineDelta); }
}
///
/// Scroll content by one line to the bottom.
///
public void LineDown()
{
if (IsScrollClient) { SetVerticalOffset(VerticalOffset + ScrollViewer._scrollLineDelta); }
}
///
/// Scroll content by one line to the left.
///
public void LineLeft()
{
if (IsScrollClient) { SetHorizontalOffset(HorizontalOffset - ScrollViewer._scrollLineDelta); }
}
///
/// Scroll content by one line to the right.
///
public void LineRight()
{
if (IsScrollClient) { SetHorizontalOffset(HorizontalOffset + ScrollViewer._scrollLineDelta); }
}
///
/// Scroll content by one page to the top.
///
public void PageUp()
{
if (IsScrollClient) { SetVerticalOffset(VerticalOffset - ViewportHeight); }
}
///
/// Scroll content by one page to the bottom.
///
public void PageDown()
{
if (IsScrollClient) { SetVerticalOffset(VerticalOffset + ViewportHeight); }
}
///
/// Scroll content by one page to the left.
///
public void PageLeft()
{
if (IsScrollClient) { SetHorizontalOffset(HorizontalOffset - ViewportWidth); }
}
///
/// Scroll content by one page to the right.
///
public void PageRight()
{
if (IsScrollClient) { SetHorizontalOffset(HorizontalOffset + ViewportWidth); }
}
///
/// Scroll content by one line to the top.
///
public void MouseWheelUp()
{
if (IsScrollClient) { SetVerticalOffset(VerticalOffset - ScrollViewer._mouseWheelDelta); }
}
///
/// Scroll content by one line to the bottom.
///
public void MouseWheelDown()
{
if (IsScrollClient) { SetVerticalOffset(VerticalOffset + ScrollViewer._mouseWheelDelta); }
}
///
/// Scroll content by one page to the top.
///
public void MouseWheelLeft()
{
if (IsScrollClient) { SetHorizontalOffset(HorizontalOffset - ScrollViewer._mouseWheelDelta); }
}
///
/// Scroll content by one page to the bottom.
///
public void MouseWheelRight()
{
if (IsScrollClient) { SetHorizontalOffset(HorizontalOffset + ScrollViewer._mouseWheelDelta); }
}
///
/// Set the HorizontalOffset to the passed value.
///
public void SetHorizontalOffset(double offset)
{
if (IsScrollClient)
{
double newValue = ValidateInputOffset(offset, "HorizontalOffset");
if (!DoubleUtil.AreClose(EnsureScrollData()._offset.X, newValue))
{
_scrollData._offset.X = newValue;
InvalidateArrange();
}
}
}
///
/// Set the VerticalOffset to the passed value.
///
public void SetVerticalOffset(double offset)
{
if (IsScrollClient)
{
double newValue = ValidateInputOffset(offset, "VerticalOffset");
if (!DoubleUtil.AreClose(EnsureScrollData()._offset.Y, newValue))
{
_scrollData._offset.Y = newValue;
InvalidateArrange();
}
}
}
///
/// ScrollContentPresenter implementation of .
///
public Rect MakeVisible(Visual visual, Rect rectangle)
{
return MakeVisible(visual, rectangle, true);
}
#endregion
//--------------------------------------------------------------------
//
// Public Properties (CLR + Avalon)
//
//--------------------------------------------------------------------
#region Public Properties
///
/// AdornerLayer on which adorners are rendered.
/// Adorners are rendered under the ScrollContentPresenter's clip region.
///
public AdornerLayer AdornerLayer
{
get { return _adornerLayer; }
}
///
/// This property indicates whether the ScrollContentPresenter should try to allow the Content
/// to scroll or not. A true value indicates Content should be allowed to scroll if it supports
/// IScrollInfo. A false value will cause ScrollContentPresenter to always act as the scrolling
/// client.
///
public bool CanContentScroll
{
get { return (bool) GetValue(CanContentScrollProperty); }
set { SetValue(CanContentScrollProperty, value); }
}
///
/// ScrollContentPresenter reacts to this property by changing it's child measurement algorithm.
/// If scrolling in a dimension, infinite space is allowed the child; otherwise, available size is preserved.
///
public bool CanHorizontallyScroll
{
get { return (IsScrollClient) ? EnsureScrollData()._canHorizontallyScroll : false; }
set
{
if (IsScrollClient && (EnsureScrollData()._canHorizontallyScroll != value))
{
_scrollData._canHorizontallyScroll = value;
InvalidateMeasure();
}
}
}
///
/// ScrollContentPresenter reacts to this property by changing it's child measurement algorithm.
/// If scrolling in a dimension, infinite space is allowed the child; otherwise, available size is preserved.
///
public bool CanVerticallyScroll
{
get { return (IsScrollClient) ? EnsureScrollData()._canVerticallyScroll : false; }
set
{
if (IsScrollClient && (EnsureScrollData()._canVerticallyScroll != value))
{
_scrollData._canVerticallyScroll = value;
InvalidateMeasure();
}
}
}
///
/// ExtentWidth contains the horizontal size of the scrolled content element in 1/96"
///
public double ExtentWidth
{
get { return (IsScrollClient) ? EnsureScrollData()._extent.Width : 0.0; }
}
///
/// ExtentHeight contains the vertical size of the scrolled content element in 1/96"
///
public double ExtentHeight
{
get { return (IsScrollClient) ? EnsureScrollData()._extent.Height : 0.0; }
}
///
/// ViewportWidth contains the horizontal size of content's visible range in 1/96"
///
public double ViewportWidth
{
get { return (IsScrollClient) ? EnsureScrollData()._viewport.Width : 0.0; }
}
///
/// ViewportHeight contains the vertical size of content's visible range in 1/96"
///
public double ViewportHeight
{
get { return (IsScrollClient) ? EnsureScrollData()._viewport.Height : 0.0; }
}
///
/// HorizontalOffset is the horizontal offset of the scrolled content in 1/96".
///
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public double HorizontalOffset
{
get { return (IsScrollClient) ? EnsureScrollData()._computedOffset.X : 0.0; }
}
///
/// VerticalOffset is the vertical offset of the scrolled content in 1/96".
///
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public double VerticalOffset
{
get { return (IsScrollClient) ? EnsureScrollData()._computedOffset.Y : 0.0; }
}
///
/// ScrollOwner is the container that controls any scrollbars, headers, etc... that are dependant
/// on this ScrollArea's properties.
///
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ScrollViewer ScrollOwner
{
get { return (IsScrollClient) ? _scrollData._scrollOwner: null; }
set { if (IsScrollClient) { _scrollData._scrollOwner = value; } }
}
///
/// DependencyProperty for property.
///
public static readonly DependencyProperty CanContentScrollProperty =
ScrollViewer.CanContentScrollProperty.AddOwner(
typeof(ScrollContentPresenter),
new FrameworkPropertyMetadata(new PropertyChangedCallback(OnCanContentScrollChanged)));
#endregion
//-------------------------------------------------------------------
//
// Protected Methods
//
//--------------------------------------------------------------------
#region Protected Methods
///
/// Returns the Visual children count.
///
protected override int VisualChildrenCount
{
get
{
// Four states make sense:
// 0 Children. No Content or AdornerLayer. Valid - do nothing.
// 2 Children. Content is first child, AdornerLayer
// One for the base.TemplateChild and one for the _adornerlayer.
return (base.TemplateChild == null) ? 0 : 2;
}
}
///
/// Returns the child at the specified index.
///
protected override Visual GetVisualChild(int index)
{
//check if there is a TemplateChild on FrameworkElement
if (base.TemplateChild == null)
{
throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange));
}
else
{
switch (index)
{
case 0:
return base.TemplateChild;
case 1:
return _adornerLayer;
default:
throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange));
}
}
}
///
/// Gets or sets the template child of the FrameworkElement.
///
override internal UIElement TemplateChild
{
get
{
return base.TemplateChild;
}
set
{
UIElement oldTemplate = base.TemplateChild;
if (value != oldTemplate)
{
if (oldTemplate != null && value == null)
{
// If we used to have a template child and we don't have a
// new template child disconnect the adorner layer.
this.RemoveVisualChild(_adornerLayer);
}
base.TemplateChild = value;
if(oldTemplate == null && value != null)
{
// If we did not use to have a template child, but we have one
// now, attach the adorner layer.
this.AddVisualChild(_adornerLayer);
}
}
}
}
///
///
protected override Size MeasureOverride(Size constraint)
{
Size desiredSize = new Size();
int count = this.VisualChildrenCount;
bool etwTracingEnabled = IsScrollClient && EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal);
if (etwTracingEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), MS.Utility.EventType.StartEvent, "SCROLLCONTENTPRESENTER:MeasureOverride");
}
if (count > 0)
{
// The AdornerLayer is always the size of our surface, and does not contribute to our own size.
_adornerLayer.Measure(constraint);
if(!IsScrollClient)
{
desiredSize = base.MeasureOverride(constraint);
}
else
{
Size childConstraint = constraint;
if (_scrollData._canHorizontallyScroll) { childConstraint.Width = Double.PositiveInfinity; }
if (_scrollData._canVerticallyScroll) { childConstraint.Height = Double.PositiveInfinity; }
desiredSize = base.MeasureOverride(childConstraint);
}
}
// If we're handling scrolling (as the physical scrolling client, validate properties.
if (IsScrollClient)
{
VerifyScrollData(constraint, desiredSize);
}
desiredSize.Width = Math.Min(constraint.Width, desiredSize.Width);
desiredSize.Height = Math.Min(constraint.Height, desiredSize.Height);
if (etwTracingEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), MS.Utility.EventType.EndEvent, "SCROLLCONTENTPRESENTER:MeasureOverride");
}
return desiredSize;
}
///
///
protected override Size ArrangeOverride(Size arrangeSize)
{
int count = this.VisualChildrenCount;
bool etwTracingEnabled = IsScrollClient && EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal);
if (etwTracingEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), MS.Utility.EventType.StartEvent, "SCROLLCONTENTPRESENTER:ArrangeOverride");
}
// Verifies IScrollInfo properties & invalidates ScrollViewer if necessary.
if (IsScrollClient)
{
VerifyScrollData(arrangeSize, _scrollData._extent);
}
if (count>0)
{
_adornerLayer.Arrange(new Rect(arrangeSize));
UIElement child = this.GetVisualChild(0) as UIElement;
if (child != null)
{
Rect childRect = new Rect(child.DesiredSize);
if (IsScrollClient)
{
childRect.X = -HorizontalOffset;
childRect.Y = -VerticalOffset;
}
//this is needed to stretch the child to arrange space,
childRect.Width = Math.Max(childRect.Width, arrangeSize.Width);
childRect.Height = Math.Max(childRect.Height, arrangeSize.Height);
child.Arrange(childRect);
}
}
if (etwTracingEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), MS.Utility.EventType.EndEvent, "SCROLLCONTENTPRESENTER:ArrangeOverride");
}
return (arrangeSize);
}
///
/// Override of .
///
/// Viewport geometry
protected override Geometry GetLayoutClip(Size layoutSlotSize)
{
return new RectangleGeometry(new Rect(RenderSize));
}
///
/// Called when the Template's tree has been generated
///
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
// Add the AdornerLayer to our visual tree.
// Iff we have content, we need an adorner layer.
// It has Content(eg. Button, TextBlock) as its first child and AdornerLayer as its second child
// Get our scrolling owner and content talking.
HookupScrollingComponents();
}
#endregion
//-------------------------------------------------------------------
//
// Internal Methods
//
//-------------------------------------------------------------------
#region Internal Methods
///
/// ScrollContentPresenter implementation of .
///
/// The Visual that should become visible
/// A rectangle representing in the visual's coordinate space to make visible.
/// If true the method throws an exception when an error is encountered, otherwise the method returns Rect.Empty when an error is encountered
///
/// A rectangle in the IScrollInfo's coordinate space that has been made visible.
/// Other ancestors to in turn make this new rectangle visible.
/// The rectangle should generally be a transformed version of the input rectangle. In some cases, like
/// when the input rectangle cannot entirely fit in the viewport, the return value might be smaller.
///
internal Rect MakeVisible(Visual visual, Rect rectangle, bool throwOnError)
{
//
//
// Note: This code presently assumes we/children are layout clean. See work item 22269 for more detail.
//
// We can only work on visuals that are us or children.
// An empty rect has no size or position. We can't meaningfully use it.
if (rectangle.IsEmpty
|| visual == null
|| visual == (Visual)this
|| !this.IsAncestorOf(visual))
{
return Rect.Empty;
}
// This is a false positive by PreSharp. visual cannot be null because of the 'if' check above
#pragma warning disable 1634, 1691
#pragma warning disable 56506
// Compute the child's rect relative to (0,0) in our coordinate space.
GeneralTransform childTransform = visual.TransformToAncestor(this);
#pragma warning restore 56506
#pragma warning restore 1634, 1691
rectangle = childTransform.TransformBounds(rectangle);
if (!IsScrollClient)
{
return rectangle;
}
// Initialize the viewport
Rect viewport = new Rect(HorizontalOffset, VerticalOffset, ViewportWidth, ViewportHeight);
rectangle.X += viewport.X;
rectangle.Y += viewport.Y;
// Compute the offsets required to minimally scroll the child maximally into view.
double minX = ComputeScrollOffsetWithMinimalScroll(viewport.Left, viewport.Right, rectangle.Left, rectangle.Right);
double minY = ComputeScrollOffsetWithMinimalScroll(viewport.Top, viewport.Bottom, rectangle.Top, rectangle.Bottom);
// We have computed the scrolling offsets; scroll to them.
SetHorizontalOffset(minX);
SetVerticalOffset(minY);
// Compute the visible rectangle of the child relative to the viewport.
viewport.X = minX;
viewport.Y = minY;
rectangle.Intersect(viewport);
if (throwOnError)
{
//
rectangle.X -= viewport.X;
rectangle.Y -= viewport.Y;
}
else
{
//
if (!rectangle.IsEmpty)
{
rectangle.X -= viewport.X;
rectangle.Y -= viewport.Y;
}
}
// Return the rectangle
return rectangle;
}
internal static double ComputeScrollOffsetWithMinimalScroll(
double topView,
double bottomView,
double topChild,
double bottomChild)
{
// # CHILD POSITION CHILD SIZE SCROLL REMEDY
// 1 Above viewport <= viewport Down Align top edge of child & viewport
// 2 Above viewport > viewport Down Align bottom edge of child & viewport
// 3 Below viewport <= viewport Up Align bottom edge of child & viewport
// 4 Below viewport > viewport Up Align top edge of child & viewport
// 5 Entirely within viewport NA No scroll.
// 6 Spanning viewport NA No scroll.
//
// Note: "Above viewport" = childTop above viewportTop, childBottom above viewportBottom
// "Below viewport" = childTop below viewportTop, childBottom below viewportBottom
// These child thus may overlap with the viewport, but will scroll the same direction/
bool fAbove = DoubleUtil.LessThan(topChild, topView) && DoubleUtil.LessThan(bottomChild, bottomView);
bool fBelow = DoubleUtil.GreaterThan(bottomChild, bottomView) && DoubleUtil.GreaterThan(topChild, topView);
bool fLarger = (bottomChild - topChild) > (bottomView - topView);
// Handle Cases: 1 & 4 above
if ((fAbove && !fLarger)
|| (fBelow && fLarger))
{
return topChild;
}
// Handle Cases: 2 & 3 above
else if (fAbove || fBelow)
{
return (bottomChild - (bottomView - topView));
}
// Handle cases: 5 & 6 above.
return topView;
}
static internal double ValidateInputOffset(double offset, string parameterName)
{
if (DoubleUtil.IsNaN(offset))
{
throw new ArgumentOutOfRangeException(parameterName, SR.Get(SRID.ScrollViewer_CannotBeNaN, parameterName));
}
return Math.Max(0.0, offset);
}
#endregion
//-------------------------------------------------------------------
//
// Private Methods
//
//--------------------------------------------------------------------
#region Private Methods
private ScrollData EnsureScrollData()
{
if (_scrollData == null) { _scrollData = new ScrollData(); }
return _scrollData;
}
// Helper method to get our ScrollViewer owner and its scrolling content talking.
// Method introduces the current owner/content, and clears a from any previous content.
internal void HookupScrollingComponents()
{
// We need to introduce our IScrollInfo to our ScrollViewer (and break any previous links).
ScrollViewer scrollContainer = TemplatedParent as ScrollViewer;
// If our content is not an IScrollInfo, we should have selected a style that contains one.
// This (readonly) style contains an AdornerDecorator with a ScrollArea child.
if (scrollContainer != null)
{
IScrollInfo si = null;
if (CanContentScroll)
{
// We need to get an IScrollInfo to introduce to the ScrollViewer.
// 1. Try our content...
si = Content as IScrollInfo;
// 2. Our child might be an ItemsPresenter. In this case check its child for being an IScrollInfo
if (si == null)
{
ItemsPresenter itemsPresenter = Content as ItemsPresenter;
if (itemsPresenter != null)
{
itemsPresenter.ApplyTemplate();
int count = VisualTreeHelper.GetChildrenCount(itemsPresenter);
if(count > 0)
si = VisualTreeHelper.GetChild(itemsPresenter, 0) as IScrollInfo;
}
}
}
// 3. As a final fallback, we use ourself.
if (si == null)
{
si = (IScrollInfo)this;
EnsureScrollData();
}
// Detach any differing previous IScrollInfo from ScrollViewer
if (si != _scrollInfo && _scrollInfo != null)
{
if (IsScrollClient) { _scrollData = null; }
else _scrollInfo.ScrollOwner = null;
}
// Introduce our ScrollViewer and IScrollInfo to each other.
if (si != null)
{
_scrollInfo = si; // At this point, we pass IsScrollClient if si == this.
si.ScrollOwner = scrollContainer;
scrollContainer.ScrollInfo = si;
}
}
// We're not really in a valid scrolling scenario. Break any previous references, and get us
// back into a totally unlinked state.
else if (_scrollInfo != null)
{
if (_scrollInfo.ScrollOwner != null) { _scrollInfo.ScrollOwner.ScrollInfo = null; }
_scrollInfo.ScrollOwner = null;
_scrollInfo = null;
_scrollData = null;
}
}
// Verifies scrolling data using the passed viewport and extent as newly computed values.
// Checks the X/Y offset and coerces them into the range [0, Extent - ViewportSize]
// If extent, viewport, or the newly coerced offsets are different than the existing offset,
// cachces are updated and InvalidateScrollInfo() is called.
private void VerifyScrollData(Size viewport, Size extent)
{
Debug.Assert(IsScrollClient);
bool fValid = true;
// These two lines of code are questionable, but they are needed right now as VSB may return
// Infinity size from measure, which is a regression from the old scrolling model.
// They also have the incidental affect of probably avoiding reinvalidation at Arrange
// when inside a parent that measures you to Infinity.
if (Double.IsInfinity(viewport.Width)) viewport.Width = extent.Width;
if (Double.IsInfinity(viewport.Height)) viewport.Height = extent.Height;
fValid &= DoubleUtil.AreClose(viewport, _scrollData._viewport);
fValid &= DoubleUtil.AreClose(extent, _scrollData._extent);
_scrollData._viewport = viewport;
_scrollData._extent = extent;
fValid &= CoerceOffsets();
if (!fValid)
{
ScrollOwner.InvalidateScrollInfo();
}
}
// Returns an offset coerced into the [0, Extent - Viewport] range.
// Internal because it is also used by other Avalon ISI implementations (just to avoid code duplication).
static internal double CoerceOffset(double offset, double extent, double viewport)
{
if (offset > extent - viewport) { offset = extent - viewport; }
if (offset < 0) { offset = 0; }
return offset;
}
private bool CoerceOffsets()
{
Debug.Assert(IsScrollClient);
Vector computedOffset = new Vector(
CoerceOffset(_scrollData._offset.X, _scrollData._extent.Width, _scrollData._viewport.Width),
CoerceOffset(_scrollData._offset.Y, _scrollData._extent.Height, _scrollData._viewport.Height));
bool fValid = DoubleUtil.AreClose(_scrollData._computedOffset, computedOffset);
_scrollData._computedOffset = computedOffset;
return fValid;
}
// This property is structurally important; we can't do layout without it set right.
// So, we synchronously make changes.
static private void OnCanContentScrollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ScrollContentPresenter scp = (ScrollContentPresenter)d;
if (scp._scrollInfo == null)
{
return;
}
//
scp.HookupScrollingComponents();
scp.InvalidateMeasure();
}
#endregion
//-------------------------------------------------------------------
//
// Private Properties
//
//--------------------------------------------------------------------
#region Private Properties
private bool IsScrollClient
{
get { return (_scrollInfo == this); }
}
//
// This property
// 1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject
// 2. This is a performance optimization
//
internal override int EffectiveValuesInitialSize
{
get { return 42; }
}
#endregion
//--------------------------------------------------------------------
//
// Private Fields
//
//-------------------------------------------------------------------
#region Private Fields
// Only one of the following will be used.
// The _scrollInfo holds a content IScrollInfo implementation that is given to the ScrollViewer.
// _scrollData holds values for the scrolling properties we use if we are handling IScrollInfo for the ScrollViewer ourself.
// ScrollData could implement IScrollInfo, but then the v-table would hurt in the common case as much as we save
// in the less common case.
private IScrollInfo _scrollInfo;
private ScrollData _scrollData;
// To hold adorners (caret, &c...) under the clipping region of the scroller.
private readonly AdornerLayer _adornerLayer;
#endregion
//------------------------------------------------------
//
// Private Structures / Classes
//
//-----------------------------------------------------
#region Private Structures Classes
//-----------------------------------------------------------
// ScrollData class
//-----------------------------------------------------------
#region ScrollData
// Helper class to hold scrolling data.
// This class exists to reduce working set when SCP is delegating to another implementation of ISI.
// Standard "extra pointer always for less data sometimes" cache savings model:
//
private class ScrollData
{
internal ScrollViewer _scrollOwner;
internal bool _canHorizontallyScroll;
internal bool _canVerticallyScroll;
internal Vector _offset; // Set scroll offset of content. Positive corresponds to a visually upward offset.
internal Vector _computedOffset; // Actual (computed) scroll offset of content. "" ""
internal Size _viewport; // ViewportSize is computed from our FinalSize, but may be in different units.
internal Size _extent; // Extent is the total size of our content.
}
#endregion ScrollData
#endregion Private Structures Classes
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MaxSessionCountExceededException.cs
- AccessControlEntry.cs
- Exceptions.cs
- FunctionImportMapping.cs
- AssociationSetEnd.cs
- NativeMethods.cs
- Light.cs
- PolicyException.cs
- DocumentPaginator.cs
- Vector3DAnimationBase.cs
- ToolStripRendererSwitcher.cs
- Point.cs
- MsmqHostedTransportManager.cs
- EventItfInfo.cs
- Typeface.cs
- EncoderFallback.cs
- SapiRecognizer.cs
- MruCache.cs
- WebServiceResponse.cs
- TdsParameterSetter.cs
- Accessible.cs
- SchemaSetCompiler.cs
- BooleanExpr.cs
- QueryResult.cs
- RouteCollection.cs
- TextTrailingWordEllipsis.cs
- ExceptionHelpers.cs
- TreeNodeBindingDepthConverter.cs
- CheckoutException.cs
- HostingEnvironmentSection.cs
- SqlDataSourceSelectingEventArgs.cs
- OneOfTypeConst.cs
- ObjectListItem.cs
- HttpCachePolicy.cs
- BaseCodePageEncoding.cs
- EventSourceCreationData.cs
- FontTypeConverter.cs
- CanonicalXml.cs
- BlurBitmapEffect.cs
- QilPatternVisitor.cs
- ConnectionStringSettings.cs
- ListViewUpdatedEventArgs.cs
- StandardCommandToolStripMenuItem.cs
- GeneralTransform.cs
- XamlFilter.cs
- IndexedString.cs
- TrailingSpaceComparer.cs
- MsmqReceiveParameters.cs
- OleStrCAMarshaler.cs
- Axis.cs
- WindowsRebar.cs
- LZCodec.cs
- ComponentCache.cs
- CodeGenerator.cs
- KeyConverter.cs
- DataSourceCache.cs
- DataGridViewRow.cs
- SHA1.cs
- HitTestDrawingContextWalker.cs
- MenuTracker.cs
- ToolStripSplitStackLayout.cs
- IpcChannelHelper.cs
- FilteredDataSetHelper.cs
- Converter.cs
- NameNode.cs
- Automation.cs
- FontUnitConverter.cs
- DataGridViewColumnCollection.cs
- TempEnvironment.cs
- FileDialogPermission.cs
- FloatUtil.cs
- bindurihelper.cs
- ParallelTimeline.cs
- MemberProjectedSlot.cs
- StateManagedCollection.cs
- CompilationUtil.cs
- ScrollProperties.cs
- OracleBFile.cs
- TableParaClient.cs
- ContainerUIElement3D.cs
- TransactionManager.cs
- BamlRecordHelper.cs
- CodeBlockBuilder.cs
- CellPartitioner.cs
- EndpointNameMessageFilter.cs
- KeyboardNavigation.cs
- tibetanshape.cs
- SQLDecimalStorage.cs
- SQLResource.cs
- CodeTypeDelegate.cs
- XPathDocument.cs
- TextBox.cs
- Utils.cs
- Token.cs
- ImageDrawing.cs
- XmlReaderDelegator.cs
- OleDbConnectionFactory.cs
- EntityStoreSchemaFilterEntry.cs
- NativeRightsManagementAPIsStructures.cs
- WmpBitmapEncoder.cs