zoukankan      html  css  js  c++  java
  • WPF SurfaceListbox 循环事件

    截图:

    (1)生成项目

    1. 打开vs2010,创建一个surface Application工程。
    2. 进入ContinuousList作为项目名称
    3. 在SurfaceWindow1.xaml文件,添加一个数据绑定SurfaceListBox控制网格控件模板的一部分。
    4. 为SurfaceListBox创建一个模板(Template)。当您完成操作之后,SurfaceWindow1.xaml文件的应用程序应该包含以下代码。

    <s:SurfaceWindow x:Class="ContinuousList.SurfaceWindow1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:s="http://schemas.microsoft.com/surface/2008"

        Title="ContinuousList"

        xmlns:l="clr-namespace:ContinuousList"

        >

      <Grid>

         

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="322"/>

                <ColumnDefinition Width="*" />

            </Grid.ColumnDefinitions>

         

            <s:SurfaceListBox Name="MainSurfaceListBox">

                <s:SurfaceListBox.ItemTemplate>

                    <DataTemplate>

                        <Image Source="{Binding}" Width="270"/>

                    </DataTemplate>

                </s:SurfaceListBox.ItemTemplate>

                <s:SurfaceListBox.Template>

                    <ControlTemplate>

                        <s:SurfaceScrollViewer

                            VerticalScrollBarVisibility="Hidden"

                            HorizontalScrollBarVisibility="Disabled"

                            CanContentScroll="true">

                            <l:LoopPanelVertical IsItemsHost="True"/>

                        </s:SurfaceScrollViewer>

                    </ControlTemplate>

                </s:SurfaceListBox.Template>

            </s:SurfaceListBox>

        </Grid>

    </s:SurfaceWindow>

            在控制模板的SurfaceListBox控制,一个SurfaceScrollViewer控制被定义。这个HorizontalScrollBarVisibility属性设置为“禁用”禁用水平滚动的控制。这个VerticalScrollBarVisibility属性设置为“隐藏”,使垂直运动不显示滚动条本身。因此,垂直平移是唯一的方法操纵内容。

            这个SurfaceScrollViewer定义使用一个自定义类,叫做LoopPanelVertical。这类源于面板并实现了ISurfaceScrollInfo接口提供定制的循环功能。这个类的进一步讨论在“创建LoopPanelVertical类”一节。

     

    (2)填充列表

    SurfaceListBox填充的控制通过使用数据绑定。早期的XAML代码建立绑定。指定的源绑定、修改SurfaceWindow1.xaml。cs文件如下:

    #region OnInitialized
    protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);
     
        // Query the registry to find out where the sample photos are stored.
        const string shellKey =
            @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\Shell Folders";
     
        string imagesPath =
            (string)Microsoft.Win32.Registry.GetValue(shellKey, "CommonPictures", null) + @"\Sample Pictures";
     
        try
        {
            // Set the ItemsSource property.
            MainSurfaceListBox.ItemsSource =
                System.IO.Directory.GetFiles(imagesPath, "*.jpg");
        }
        catch (System.IO.DirectoryNotFoundException)
        {
            // Handle exceptions as needed.
        }
    }
    #endregion

    (3)创建LoopPanelVertical类

    LoopPanelVertical的类实现了ISurfaceScrollInfo接口启用连续循环的内容SurfaceScrollViewer控制。LoopPanelVertical的实现分为以下几部分。

    #region AllCode
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Media;
    using Microsoft.Surface.Presentation;
    using Microsoft.Surface.Presentation.Controls;
    using Microsoft.Surface.Presentation.Controls.Primitives;
     
    namespace ContinuousList
    {
        public partial class LoopPanelVertical : Panel, ISurfaceScrollInfo
        {
            private ScrollViewer owner;
            private Size extent = new Size(0, 0);
            private Size viewport = new Size(0, 0);
            private Point viewportOffset = new Point();
            private bool viewportPositionDirty;
            private bool verticalScrollAllowed;
            private int firstItem;
            private double firstItemOffset;
            private double previousOffset = double.NaN;
            private double totalContentHeight;
     
            // Constructor
            public LoopPanelVertical()
            {
                this.RenderTransform = new TranslateTransform();
            }
     
            #region IScrollInfo Properties
            // Gets or sets a value that determines if the content can be scrolled horizontally.
            public bool CanHorizontallyScroll
            {
                get
                {
                    return false;
                }
                set
                {
                    if (value)
                    {
                        throw new NotSupportedException();
                    }
                }
            }
     
            // Gets or sets a value that determines if the content can be scrolled vertically.
            public bool CanVerticallyScroll
            {
                get
                {
                    return verticalScrollAllowed;
                }
                set
                {
                    verticalScrollAllowed = value;
                }
            }
     
            // Gets a value that describes the height of the area.
            public double ExtentHeight
            {
                get { return extent.Height; }
            }
     
            // Gets a value that describes the width of the area.
            public double ExtentWidth
            {
                get { return extent.Width; }
            }
     
            /// Gets a value that describes the vertical offset of the view box.
            public double VerticalOffset
            {
                get { return viewportOffset.Y; }
            }
     
     
            // Gets a value that describes the horizontal offset of the view box.
            public double HorizontalOffset
            {
                get { return viewportOffset.X; }
            }
     
            // Gets a value that describes the height of the viewport.
            public double ViewportHeight
            {
                get { return viewport.Height; }
            }
     
            // Gets a value that describes the width of the viewport.
            public double ViewportWidth
            {
                get { return viewport.Width; }
            }
     
            // Gets or sets the owner.
            public ScrollViewer ScrollOwner
            {
                get
                {
                    return this.owner;
                }
                set
                {
                    this.owner = value;
                }
            }
            #endregion
     
            #region IScrollInfo Positioning Methods
            // Scroll content up.
            public void LineUp()
            {
                ScrollContent(-1);
            }
     
            // Scroll content down.
            public void LineDown()
            {
                ScrollContent(1);
            }
     
            public void LineLeft()
            {
                // Not implemented. Cannot scroll horizontally.
            }
     
            public void LineRight()
            {
                // Not implemented. Cannot scroll horizontally.
            }
     
            // Scrolls the content up by ten lines.
            public void MouseWheelUp()
            {
                ScrollContent(10);
            }
     
            // Scrolls the content down by ten lines. 
            public void MouseWheelDown()
            {
                ScrollContent(-10);
            }
     
            public void MouseWheelLeft()
            {
                // Not implemented. Cannot scroll horizontally.
            }
     
            public void MouseWheelRight()
            {
                // Not implemented. Cannot scroll horizontally. 
            }
     
            public void PageUp()
            {
                ScrollContent(-viewport.Height);
            }
     
            public void PageDown()
            {
                ScrollContent(viewport.Height);
            }
     
            public void PageLeft()
            {
                // Not implemented. Cannot scroll horizontally.
            }
     
            public void PageRight()
            {
                // Not implemented. Cannot scroll horizontally.
            }
            #endregion
     
            #region IScrollInfo Offset Methods
            public void SetVerticalOffset(double newOffset)
            {
                if (CanVerticallyScroll)
                {
                    // Make sure the offset is set for the current inputs.
                    if (double.IsNaN(previousOffset))
                    {
                        previousOffset = newOffset;
                    }
     
                    // Calculate the movement delta.
                    double difference = previousOffset - newOffset;
     
                    // Scroll the content.
                    ScrollContent(difference);
     
                    // Update the offset for next time.
                    previousOffset = newOffset;
                }
            }
     
            public void SetHorizontalOffset(double newOffset)
            {
                // Not implemented. Cannot scroll horizontally.
            }
            #endregion
     
            #region IScrollInfo MakeVisible Method
            public Rect MakeVisible(Visual visual, Rect rectangle)
            {
                int itemIndex = Children.IndexOf((UIElement)visual);
                int index = firstItem;
                double itemOffset = firstItemOffset;
     
                // Get the offset for the item that should be visible.
                while (index != itemIndex)
                {
                    itemOffset += Children[index].DesiredSize.Height;
                    index++;
                    if (index >= Children.Count)
                    {
                        index = 0;
                    }
                }
     
                // If the item is not fully in view on the top, 
                // adjust the offset to bring it into view.
                if (itemOffset < viewportOffset.Y)
                {
                    ScrollContent(viewportOffset.Y - itemOffset);
                }
     
                // If the item is not fully in view on the bottom, 
                // adjust the offset to bring it into view.
                if (itemOffset + rectangle.Height > viewportOffset.Y + ViewportHeight)
                {
                    ScrollContent((viewportOffset.Y + ViewportHeight) - 
                        (itemOffset + rectangle.Height));
                }
     
                return rectangle;
            }
            #endregion
     
            #region ISurfaceScrollInfo Members
            public Vector ConvertFromViewportUnits(Point origin, Vector offset)
            {
                return offset;
            }
     
            public Vector ConvertToViewportUnits(Point origin, Vector offset)
            {
                return offset;
            }
     
            public Vector ConvertToViewportUnitsForFlick(Point origin, Vector offset)
            {
                return offset;
            }
            #endregion
     
            #region Overridden Layout Methods
            protected override Size MeasureOverride(Size availableSize)
            {
                // If there's no children, take all the space.
                if (this.InternalChildren.Count == 0)
                {
                    return availableSize;
                }
     
                // Measure each of the child items. Keep a running sum of heights.
                // Used later to measure the viewport and the extent.
                this.totalContentHeight = 0;
                foreach (UIElement child in this.InternalChildren)
                {
                    child.Measure(availableSize);
                    this.totalContentHeight += child.DesiredSize.Height;
                }
     
                // The viewport should be as large as it can be.
                this.viewport = availableSize;
     
                // Remeasuring could invalidate the current viewport position. Mark it as dirty.
                this.viewportPositionDirty = true;
     
                return availableSize;
            }
            
            protected override Size ArrangeOverride(Size finalSize)
            {
                // If there's no children, take all the space.
                if (this.InternalChildren.Count == 0)
                {
                    return finalSize;
                }
     
                // Arrange the viewport relative to the extent.
                if (this.viewportPositionDirty)
                {
                    PositionViewportAndExtent();
                }
     
                double nextDrawingPosition = firstItemOffset;
                Rect arrangeInMe;
     
                // From first item to end
                for (int i = firstItem; i < InternalChildren.Count; i++)
                {
                    UIElement item = InternalChildren[i];
                    arrangeInMe = 
                        new Rect(0, nextDrawingPosition, 
                            item.DesiredSize.Width, 
                            item.DesiredSize.Height);
                    item.Arrange(arrangeInMe);
                    nextDrawingPosition += item.DesiredSize.Height;
                }
     
                // From child zero to firstItem - 1
                for (int i = 0; i < firstItem; i++)
                {
                    UIElement item = InternalChildren[i];
                    arrangeInMe = 
                        new Rect(0, nextDrawingPosition, 
                            item.DesiredSize.Width, 
                            item.DesiredSize.Height);
                    item.Arrange(arrangeInMe);
                    nextDrawingPosition += item.DesiredSize.Height;
                }
     
                return finalSize;
            }
            #endregion
     
            #region Viewport and Extent Methods
            private void PositionViewportAndExtent()
            {
                // If the items all fit in the viewport at the same time, 
                // disable scrolling and center the items.
                if (totalContentHeight < viewport.Height)
                {
                    extent = new Size(viewport.Width, totalContentHeight);
                    SetViewport(0);
                    firstItemOffset = (viewport.Height - totalContentHeight) / 2;
                    CanVerticallyScroll = false;
                }
     
                // Otherwise, extend the extent past both ends of the viewport 
                // so there will be plenty of space in which to scroll the items.
                else
                {
                    // Make sure the extent is plenty large. 
                    extent = new Size(viewport.Width, Math.Max(1000000, totalContentHeight * 15));
                    SetViewport((extent.Height - viewport.Height) / 2);
                    firstItemOffset = (extent.Height - totalContentHeight) / 2;
                    CanVerticallyScroll = true;
                }
     
                viewportPositionDirty = false;
     
                // Because the offset was changed, the current scroll info isn't valid anymore.
                if (owner != null)
                {
                    owner.InvalidateScrollInfo();
                }
            }
            
            private void SetViewport(double newOffset)
            {
                // Validate the input.
                if (newOffset < 0 || viewport.Height >= extent.Height)
                {
                    newOffset = 0;
                }
     
                if (newOffset + viewport.Height >= extent.Height)
                {
                    newOffset = extent.Height - viewport.Height;
                }
     
                // Value is validated, so use it.
                viewportOffset.Y = newOffset;
     
                // Adjust the transform to display based on the new offset.
                ((TranslateTransform)this.RenderTransform).Y = -newOffset;
     
                // Balance the content around the viewport.
                double firstItemBottom = 
                    firstItemOffset + InternalChildren[firstItem].DesiredSize.Height;
                int lastItemIndex = 
                    firstItem <= 0 ? InternalChildren.Count - 1 : firstItem - 1;
                double lastItemTop = 
                    firstItemOffset + totalContentHeight - InternalChildren[lastItemIndex].DesiredSize.Height;
     
                // Move items as needed.
                if (viewportOffset.Y < firstItemBottom)
                {
                    MoveItemsFromBottomToTop();
                }
     
                if (viewportOffset.Y + ViewportHeight > lastItemTop)
                {
                    MoveItemsFromTopToBottom();
                }
            }
     
            // Called by various other methods.
            private void ScrollContent(double adjustment)
            {
                SetViewport(viewportOffset.Y - adjustment);
            }
            #endregion
            
            #region Move Item Methods
            private void MoveItemsFromBottomToTop()
            {
                // Move from the left to the right 
                // until the first item that is not in the viewport.
                int index = firstItem;
                double itemTopOffset = firstItemOffset;
                int itemsInViewport = 0;
     
                // Step through the items from the top, and
                // count how many items are in the viewport.
                while (itemTopOffset < viewportOffset.Y + ViewportHeight)
                {
                    itemsInViewport++;
                    itemTopOffset += InternalChildren[index].DesiredSize.Height;
                    index = index >= InternalChildren.Count - 1 ? 0 : index + 1;
                }
     
                // The items that are not in the viewport should be distributed
                // so there are some on either side of the viewport. 
                // It's likely that the viewport will continue to be moved in the 
                // direction it is currently being moved.
                // Move 2/3 of the items, and leave 1/3 where they are.
                int itemsNotInViewport = InternalChildren.Count - itemsInViewport;
                int itemsToRemainInPlace = itemsNotInViewport / 3;
     
                // Skip past the items that will remain in place.
                for (int i = 0; i < itemsToRemainInPlace; i++)
                {
                    itemTopOffset += InternalChildren[index].DesiredSize.Height;
                    index = index >= InternalChildren.Count - 1 ? 0 : index + 1;
                }
     
                // Find the amount by which firstItemOffset needs to be adjusted.
                double movedHeight = firstItemOffset + totalContentHeight - itemTopOffset;
     
                // Change the first item index, and adjust the offset to match.
                firstItemOffset -= movedHeight;
                firstItem = index;
     
                // Need to redraw the items.
                InvalidateVisual();
            }
     
            private void MoveItemsFromTopToBottom()
            {
                // Move from the top to bottom 
                // until the first item that is not in the viewport.
                int index = firstItem <= 0 ? InternalChildren.Count - 1 : firstItem - 1;
                double itemBottomOffset = firstItemOffset + totalContentHeight;
                int itemsInViewport = 0;
     
                // Step through the items from the bottom, and
                // count how many items are in the viewport.
                while (itemBottomOffset > viewportOffset.Y)
                {
                    itemsInViewport++;
                    itemBottomOffset -= InternalChildren[index].DesiredSize.Height;
                    index = index <= 0 ? InternalChildren.Count - 1 : index - 1;
                }
     
                // The items that are not in the viewport should be distributed
                // so there are some on either side of the viewport. 
                // It's likely that the viewport will continue to be moved in the 
                // direction it is currently being moved.
                // Move 2/3 of the items, and leave 1/3 where they are.
                int itemsNotInViewport = InternalChildren.Count - itemsInViewport;
                int itemsToRemain = itemsNotInViewport / 3;
     
                // Skip past the items that will remain in place.
                for (int i = 0; i < itemsToRemain; i++)
                {
                    itemBottomOffset -= InternalChildren[index].DesiredSize.Height;
                    index = index <= 0 ? InternalChildren.Count - 1 : index - 1;
                }
     
                // Find the amount by which firstItemOffset needs to be adjusted.
                double movedHeight = itemBottomOffset - firstItemOffset;
     
                // Change the first item index, and adjust the offset to match.
                firstItemOffset += movedHeight;
                firstItem = index >= InternalChildren.Count - 1 ? 0 : index + 1;
     
                // Need to redraw the items.
                InvalidateVisual();
            }
            #endregion
        } // end Class LoopPanelVertical
    }
    #endregion
  • 相关阅读:
    WEP编码格式
    OSK VFS read数据流分析
    科学剖析濒死体验 "复生"者讲述"死"前1秒钟
    Android的开发相对于tizen的开发难度
    minix文件系统分析
    贴给小程序(1) 查找第一个0值
    Linux下的QQ
    OSK USB 驱动
    LRU算法之hash+list实现(转)
    插入排序
  • 原文地址:https://www.cnblogs.com/DeepBlues/p/2918330.html
Copyright © 2011-2022 走看看