Vývoj moderních aplikací na platformě Microsoft .NET

Je vyžadována podpora jazyka JavaScript

Některé stránky na tomto webu vyžadují podporu jazyka JavaScript. Váš webový prohlížeč jazyk JavaScript nepodporuje nebo jazyk JavaScript není povolen.

Chcete-li zjistit, zda webový prohlížeč podporuje jazyk JavaScript nebo jazyk JavaScript chcete povolit, přečtěte si nápovědu k vašemu webovému prohlížeči.


scrollablewrappanel.cs

Download file

Toto je zdrojový kód souboru scrollablewrappanel.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.ComponentModel;

namespace IMP.Windows.Controls
{
    /// <summary>
    /// WrapPanel with IScrollInfo support
    /// </summary>
    /// <remarks>
    /// Add <c>VerticalScrollChange</c> and <c>HorizontalScrollChange</c> properties
    /// </remarks>
    public partial class ScrollableWrapPanel : WrapPanel, System.Windows.Controls.Primitives.IScrollInfo
    {
        #region constants
        private const double cDefaultVerticalScrollChange = 22.0;
        private const double cDefaultHorizontalScrollChange = 66.0;
        #endregion

        #region member varible and default property initialization
        private bool m_CanHorizontallyScroll;
        private bool m_CanVerticallyScroll;
        private ScrollViewer m_ScrollOwner;
        private Vector m_Offset;
        private Size m_Extent;
        private Size m_Viewport;
        #endregion

        #region action methods
        /// <summary>
        /// Scrolls up within the content by one logical unit.
        /// </summary>
        public virtual void LineUp()
        {
            this.SetVerticalOffset(this.VerticalOffset - this.VerticalScrollChange);
        }

        /// <summary>
        /// Scrolls down within the content by one logical unit.
        /// </summary>
        public virtual void LineDown()
        {
            this.SetVerticalOffset(this.VerticalOffset + this.VerticalScrollChange);
        }

        /// <summary>
        /// Scrolls left within the content by one logical unit.
        /// </summary>
        public virtual void LineLeft()
        {
            this.SetHorizontalOffset(this.HorizontalOffset - this.HorizontalScrollChange);
        }

        /// <summary>
        /// Scrolls right within the content by one logical unit.
        /// </summary>
        public virtual void LineRight()
        {
            this.SetHorizontalOffset(this.HorizontalOffset + this.HorizontalScrollChange);
        }

        /// <summary>
        /// Scrolls up within the content after the user clicks the wheel button on a mouse.
        /// </summary>
        public virtual void MouseWheelUp()
        {
            this.SetVerticalOffset(this.VerticalOffset - (SystemParameters.WheelScrollLines * this.VerticalScrollChange));
        }

        /// <summary>
        /// Scrolls down within the content after the user clicks the wheel button on a mouse.
        /// </summary>
        public virtual void MouseWheelDown()
        {
            this.SetVerticalOffset(this.VerticalOffset + (SystemParameters.WheelScrollLines * this.VerticalScrollChange));
        }

        /// <summary>
        /// Scrolls left within the content after the user clicks the wheel button on a mouse.
        /// </summary>
        public virtual void MouseWheelLeft()
        {
            this.SetHorizontalOffset(this.HorizontalOffset - (3.0 * this.HorizontalScrollChange));
        }

        /// <summary>
        /// Scrolls right within the content after the user clicks the wheel button on a mouse.
        /// </summary>
        public virtual void MouseWheelRight()
        {
            this.SetHorizontalOffset(this.HorizontalOffset + (3.0 * this.HorizontalScrollChange));
        }

        /// <summary>
        /// Scrolls up within the content by one page.
        /// </summary>
        public virtual void PageUp()
        {
            this.SetVerticalOffset(this.VerticalOffset - this.ViewportHeight);
        }

        /// <summary>
        /// Scrolls down within the content by one page.
        /// </summary>
        public virtual void PageDown()
        {
            this.SetVerticalOffset(this.VerticalOffset + this.ViewportHeight);
        }

        /// <summary>
        /// Scrolls left within the content by one page.
        /// </summary>
        public virtual void PageLeft()
        {
            this.SetHorizontalOffset(this.HorizontalOffset - this.ViewportWidth);
        }

        /// <summary>
        /// Scrolls right within the content by one page.
        /// </summary>
        public virtual void PageRight()
        {
            this.SetHorizontalOffset(this.HorizontalOffset + this.ViewportWidth);
        }

        /// <summary>
        /// Sets the amount of horizontal offset.
        /// </summary>
        /// <param name="offset">The amount that content is horizontally offset from the containing viewport.</param>
        public void SetHorizontalOffset(double offset)
        {
            if (this.CanHorizontallyScroll)
            {
                double X = Math.Max(0.0, Math.Min(offset, this.ExtentWidth - this.ViewportWidth));
                if (X != m_Offset.X)
                {
                    m_Offset.X = X;
                    this.InvalidateArrange();
                }
            }
        }

        /// <summary>
        /// Sets the amount of vertical offset.
        /// </summary>
        /// <param name="offset">The amount that content is vertically offset from the containing viewport.</param>
        public void SetVerticalOffset(double offset)
        {
            if (this.CanVerticallyScroll)
            {
                double Y = Math.Max(0.0, Math.Min(offset, this.ExtentHeight - this.ViewportHeight));
                if (Y != m_Offset.Y)
                {
                    m_Offset.Y = Y;
                    base.InvalidateArrange();
                }
            }
        }

        /// <summary>
        /// Forces content to scroll until the coordinate space of a visual object is visible.
        /// </summary>
        /// <param name="visual">A System.Windows.UIElement that becomes visible.</param>
        /// <param name="rectangle">A bounding rectangle that identifies the coordinate space to make visible.</param>
        /// <returns>A System.Windows.Rect that is visible.</returns>
        public Rect MakeVisible(UIElement visual, Rect rectangle)
        {
            if (rectangle.IsEmpty || visual == null || visual == this || !IsAncestorOf(visual))
            {
                return Rect.Empty;
            }

            Point point = visual.TransformToVisual(this).Transform(new Point(rectangle.X, rectangle.Y));
            rectangle.X = point.X;
            rectangle.Y = point.Y;

            Rect viewRect = new Rect(this.HorizontalOffset, this.VerticalOffset, this.ViewportWidth, this.ViewportHeight);
            rectangle.X += viewRect.X;
            rectangle.Y += viewRect.Y;

            double X = ComputeScrollOffset(viewRect.Left, viewRect.Right, rectangle.Left, rectangle.Right);
            double Y = ComputeScrollOffset(viewRect.Top, viewRect.Bottom, rectangle.Top, rectangle.Bottom);
            this.SetHorizontalOffset(X);
            this.SetVerticalOffset(Y);
            viewRect.X = X;
            viewRect.Y = Y;

            rectangle.Intersect(viewRect);
            if (!rectangle.IsEmpty)
            {
                rectangle.X -= viewRect.X;
                rectangle.Y -= viewRect.Y;
            }

            return rectangle;
        }
        #endregion

        #region property getters/setters
        /// <summary>
        /// VerticalScrollChange dependency property
        /// </summary>
        public static readonly DependencyProperty VerticalScrollChangeProperty = DependencyProperty.Register("VerticalScrollChange", typeof(double), typeof(ScrollableWrapPanel), new PropertyMetadata(cDefaultVerticalScrollChange));

        /// <summary>
        /// Vertical Scroll Change 
        /// </summary>
        [DefaultValue(cDefaultVerticalScrollChange)]
        public double VerticalScrollChange
        {
            get { return (double)base.GetValue(VerticalScrollChangeProperty); }
            set { base.SetValue(VerticalScrollChangeProperty, value); }
        }

        /// <summary>
        /// HorizontalScrollChange dependency property
        /// </summary>
        public static readonly DependencyProperty HorizontalScrollChangeProperty = DependencyProperty.Register("HorizontalScrollChange", typeof(double), typeof(ScrollableWrapPanel), new PropertyMetadata(cDefaultHorizontalScrollChange));

        /// <summary>
        /// Horizontal Scroll Change
        /// </summary>
        [DefaultValue(cDefaultHorizontalScrollChange)]
        public double HorizontalScrollChange
        {
            get { return (double)base.GetValue(HorizontalScrollChangeProperty); }
            set { base.SetValue(HorizontalScrollChangeProperty, value); }
        }

        /// <summary>
        /// Gets the horizontal offset of the scrolled content.
        /// </summary>
        public double HorizontalOffset
        {
            get { return m_Offset.X; }
        }

        /// <summary>
        /// Gets the vertical offset of the scrolled content.
        /// </summary>
        public double VerticalOffset
        {
            get { return m_Offset.Y; }
        }

        /// <summary>
        /// Gets the vertical size of the extent.
        /// </summary>
        public double ExtentHeight
        {
            get { return m_Extent.Height; }
        }

        /// <summary>
        /// Gets the horizontal size of the extent.
        /// </summary>
        public double ExtentWidth
        {
            get { return m_Extent.Width; }
        }

        /// <summary>
        /// Gets the vertical size of the viewport for this content.
        /// </summary>
        public double ViewportHeight
        {
            get { return m_Viewport.Height; }
        }

        /// <summary>
        /// Gets the horizontal size of the viewport for this content.
        /// </summary>
        public double ViewportWidth
        {
            get { return m_Viewport.Width; }
        }

        /// <summary>
        /// Gets or sets a value that indicates whether scrolling on the horizontal axis is possible.
        /// </summary>
        public bool CanHorizontallyScroll
        {
            get { return m_CanHorizontallyScroll; }
            set { m_CanHorizontallyScroll = value; }
        }

        /// <summary>
        /// Gets or sets a value that indicates whether scrolling on the vertical axis is possible.
        /// </summary>
        public bool CanVerticallyScroll
        {
            get { return m_CanVerticallyScroll; }
            set { m_CanVerticallyScroll = value; }
        }

        /// <summary>
        /// Gets or sets a System.Windows.Controls.ScrollViewer element that controls scrolling behavior.
        /// </summary>
        public ScrollViewer ScrollOwner
        {
            get { return m_ScrollOwner; }
            set { m_ScrollOwner = value; }
        }
        #endregion

        #region override methods
        /// <summary>
        /// Overrides MeasureOverride
        /// </summary>
        protected override Size MeasureOverride(Size constraint)
        {
            var desiredSize = base.MeasureOverride(constraint);

            this.VerifyScrollData(constraint, desiredSize);

            return desiredSize;
        }

        /// <summary>
        /// Overrides ArrangeOverride
        /// </summary>
        protected override Size ArrangeOverride(Size arrangeSize)
        {
            var size = base.ArrangeOverride(arrangeSize);

            for (int i = 0; i < Children.Count; i++)
            {
                UIElement element = Children[i];
                Size desiredSize = element.DesiredSize;

                var gt = element.TransformToVisual(this);
                var pos = gt.Transform(new Point(0, 0));

                var finalRect = new Rect(pos.X - m_Offset.X, pos.Y - m_Offset.Y, desiredSize.Width, desiredSize.Height);
                element.Arrange(finalRect);
            }

            return size;
        }
        #endregion

        #region private member functions
        private void VerifyScrollData(Size viewport, Size extent)
        {
            m_Viewport = viewport;
            m_Extent = extent;

            if (m_Offset.X > (m_Extent.Width - m_Viewport.Width))
            {
                m_Offset.X = m_Extent.Width - m_Viewport.Width;
            }
            if (m_Offset.X < 0.0)
            {
                m_Offset.X = 0.0;
            }

            if (m_Offset.Y > (m_Extent.Height - m_Viewport.Height))
            {
                m_Offset.Y = m_Extent.Height - m_Viewport.Height;
            }
            if (m_Offset.Y < 0.0)
            {
                m_Offset.Y = 0.0;
            }

            if (this.ScrollOwner != null)
            {
                this.ScrollOwner.InvalidateScrollInfo();
            }
        }

        private bool IsAncestorOf(UIElement element)
        {
            UIElement panel = this;
            UIElement reference = element;
            while (reference != null && reference != panel)
            {
                reference = VisualTreeHelper.GetParent(reference) as UIElement;
            }

            return reference == panel;
        }

        private static double ComputeScrollOffset(double topView, double bottomView, double topChild, double bottomChild)
        {
            bool offBottom = topChild < topView && bottomChild < bottomView;
            bool offTop = bottomChild > bottomView && topChild > topView;
            bool tooLarge = (bottomChild - topChild) > (bottomView - topView);

            if (!offBottom && !offTop)
            {
                //Don't do anything, already in view
                return topView;
            }

            if ((offBottom && !tooLarge) || (offTop && tooLarge))
            {
                return topChild;
            }

            return (bottomChild - (bottomView - topView));
        }
        #endregion
    }
}