Advertisement
Guest User

SnapList.xaml.cs

a guest
Apr 24th, 2013
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 12.22 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Data;
  8. using System.Windows.Documents;
  9. using System.Windows.Input;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Imaging;
  12. using System.Windows.Navigation;
  13. using System.Windows.Shapes;
  14. using Microsoft.Surface.Presentation.Controls;
  15. using System.Windows.Media.Animation;
  16. using System.Collections.Specialized;
  17. using System.Collections;
  18. using System.Windows.Threading;
  19. using System.Timers;
  20.  
  21. namespace ATypeSurfaceControls
  22. {
  23.     /// <summary>
  24.     /// Interaction logic for SnapList.xaml
  25.     /// </summary>
  26.     public partial class SnapList : UserControl
  27.     {
  28.         const double VERTICAL_TAKEOVER_TOLERANCE = 15;
  29.  
  30.         SurfaceScrollViewer ss;
  31.         private bool coasting;
  32.  
  33.         #region dependency properties
  34.         #region item properties
  35.         public IEnumerable ItemsSource
  36.         {
  37.             get { return (IEnumerable)GetValue(ItemsSourceProperty); }
  38.             set { SetValue(ItemsSourceProperty, value); }
  39.         }
  40.         public static readonly DependencyProperty ItemsSourceProperty =
  41.             DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(SnapList), new PropertyMetadata(null));
  42.  
  43.         public DataTemplate ItemContentTemplate
  44.         {
  45.             get { return (DataTemplate)GetValue(ItemContentTemplateProperty); }
  46.             set { SetValue(ItemContentTemplateProperty, value); }
  47.         }
  48.         public static readonly DependencyProperty ItemContentTemplateProperty =
  49.             DependencyProperty.Register("ItemContentTemplate", typeof(DataTemplate), typeof(SnapList), new UIPropertyMetadata(null));
  50.        
  51.         public ControlTemplate ItemTemplate
  52.         {
  53.             get { return (ControlTemplate)GetValue(ItemTemplateProperty); }
  54.             set { SetValue(ItemTemplateProperty, value); }
  55.         }
  56.         public static readonly DependencyProperty ItemTemplateProperty =
  57.             DependencyProperty.Register("ItemTemplate", typeof(ControlTemplate), typeof(SnapList), new UIPropertyMetadata(null));
  58.         #endregion
  59.         #region behavior
  60.  
  61.  
  62.         public double SnapSpeed
  63.         {
  64.             get { return (double)GetValue(SnapSpeedProperty); }
  65.             set { SetValue(SnapSpeedProperty, value); }
  66.         }
  67.  
  68.         // Using a DependencyProperty as the backing store for SnapSpeed.  This enables animation, styling, binding, etc...
  69.         public static readonly DependencyProperty SnapSpeedProperty =
  70.             DependencyProperty.Register("SnapSpeed", typeof(double), typeof(SnapList), new UIPropertyMetadata(0.1));
  71.  
  72.  
  73.         /// <summary>
  74.         /// The element the list should snap relative to - it will aim for the center of this element, if one is specified. If not, the window.
  75.         /// </summary>
  76.         public FrameworkElement RelativeParent
  77.         {
  78.             get { return (FrameworkElement)GetValue(RelativeParentProperty); }
  79.             set { SetValue(RelativeParentProperty, value); }
  80.         }
  81.  
  82.         // Using a DependencyProperty as the backing store for RelativeParent.  This enables animation, styling, binding, etc...
  83.         public static readonly DependencyProperty RelativeParentProperty =
  84.             DependencyProperty.Register("RelativeParent", typeof(FrameworkElement), typeof(SnapList), new UIPropertyMetadata(null));
  85.  
  86.  
  87.         /// <summary>
  88.         /// A custom-defined center point for the list to snap to.
  89.         /// </summary>
  90.         public double CustomCenter
  91.         {
  92.             get { return (double)GetValue(CustomCenterProperty); }
  93.             set { SetValue(CustomCenterProperty, value); }
  94.         }
  95.  
  96.         // Using a DependencyProperty as the backing store for CustomCenter.  This enables animation, styling, binding, etc...
  97.         public static readonly DependencyProperty CustomCenterProperty =
  98.             DependencyProperty.Register("CustomCenter", typeof(double), typeof(SnapList), new UIPropertyMetadata(0.5));
  99.  
  100.        
  101.         #endregion        
  102.         #endregion      
  103.  
  104.         #region events
  105.         public event SelectionChangedEventHandler SelectionChanged;
  106.         public event EventHandler ReachedBottom;
  107.         #endregion
  108.  
  109.         public SnapList()
  110.         {
  111.             InitializeComponent();
  112.             Loaded += new RoutedEventHandler(SnapList_Loaded);
  113.         }
  114.  
  115.         void SnapList_Loaded(object sender, RoutedEventArgs e)
  116.         {
  117.             ss = VisualTreeHelper.GetChild(List, 0) as SurfaceScrollViewer;
  118.             Mediator.ScrollViewer = ss;
  119.  
  120.             List.SelectionMode = SelectionMode.Single;
  121.  
  122.             ss.ScrollChanged += new ScrollChangedEventHandler(ss_ScrollChanged);
  123.  
  124.             AddHandler(SurfaceScrollViewer.ManipulationCompletedEvent, new EventHandler<ManipulationCompletedEventArgs>(ManipCompleted), true);
  125.             AddHandler(SurfaceScrollViewer.ManipulationStartingEvent, new EventHandler<ManipulationStartingEventArgs>(ManipStarting), true);
  126.  
  127.             List.SelectionChanged += new SelectionChangedEventHandler(List_SelectionChanged);
  128.             if (List.HasItems)
  129.                 ScrollToIndex(0);
  130.  
  131.             DispatcherTimer cleanup = new DispatcherTimer(TimeSpan.FromSeconds(1), DispatcherPriority.Background, new EventHandler(OnCleanupTimer), Dispatcher);
  132.             cleanup.Start();
  133.         }
  134.  
  135.         void ss_ScrollChanged(object sender, ScrollChangedEventArgs e)
  136.         {
  137.             if (List.HasItems && e.VerticalOffset + e.VerticalChange >= ss.ExtentHeight - ss.ViewportHeight)
  138.             {
  139.                 if (ReachedBottom != null)
  140.                     ReachedBottom(this, null);
  141.             }
  142.         }
  143.  
  144.         void List_SelectionChanged(object sender, SelectionChangedEventArgs e)
  145.         {
  146.             if (this.SelectionChanged != null)
  147.             {
  148.                 this.SelectionChanged(this, e);
  149.             }
  150.         }
  151.  
  152.         void ManipStarting(object sender, ManipulationStartingEventArgs e)
  153.         {
  154.             coasting = true;
  155.         }
  156.  
  157.         void ManipCompleted(object sender, ManipulationCompletedEventArgs e)
  158.         {
  159.             coasting = false;
  160.             List<FrameworkElement> visibleElements = new List<FrameworkElement>();
  161.             for (int i = 0; i < List.Items.Count; i++)
  162.             {
  163.                 SurfaceListBoxItem item = List.ItemContainerGenerator.ContainerFromIndex(i) as SurfaceListBoxItem;
  164.                 if (ViewportHelper.IsInViewport(item))
  165.                 {
  166.                     FrameworkElement el = item as FrameworkElement;
  167.                     visibleElements.Add(el);
  168.                 }
  169.             }
  170.  
  171.             FrameworkElement window = RelativeParent == null ? List : RelativeParent;
  172.  
  173.             double center = ss.ViewportHeight * CustomCenter;
  174.  
  175.             double closestCenterOffset = double.MaxValue;
  176.             FrameworkElement centerItem = visibleElements.Count > 0 ? visibleElements[0] :
  177.                 List.ItemContainerGenerator.ContainerFromIndex(1) as FrameworkElement;
  178.             foreach (FrameworkElement el in visibleElements)
  179.             {
  180.                 double centerOffset = Math.Abs(el.TransformToAncestor(window).Transform(new Point(0, 0)).Y + (el.ActualHeight / 2) - center);
  181.                 if (centerOffset < closestCenterOffset)
  182.                 {
  183.                     closestCenterOffset = centerOffset;
  184.                     centerItem = el;
  185.                 }
  186.             }
  187.  
  188.             ScrollToItem(centerItem);
  189.         }
  190.  
  191.         public void ScrollToItem(FrameworkElement centerItem)
  192.         {
  193.             if (centerItem == null)
  194.                 return;
  195.             if (ss == null)
  196.                 return;
  197.  
  198.             double center = ss.ViewportHeight * CustomCenter;
  199.  
  200.             FrameworkElement window = RelativeParent == null ? Window.GetWindow(this) : RelativeParent;
  201.  
  202.             Point itemPosition = centerItem.TransformToAncestor(window).Transform(new Point(0, 0));
  203.  
  204.             double desiredOffset = ss.VerticalOffset - (center - itemPosition.Y) + (centerItem.ActualHeight / 2);
  205.  
  206.             DoubleAnimation scrollAnim = new DoubleAnimation();
  207.             scrollAnim.From = ss.VerticalOffset;
  208.             scrollAnim.To = desiredOffset;
  209.             scrollAnim.Duration = new Duration(TimeSpan.FromSeconds(SnapSpeed));
  210.             Mediator.BeginAnimation(ScrollViewerOffsetMediator.VerticalOffsetProperty, scrollAnim);
  211.  
  212.  
  213.             SurfaceListBoxItem li = (SurfaceListBoxItem)centerItem;
  214.             //List.SelectedItem = li;
  215.             li.IsSelected = true;
  216.  
  217.             //check if scroll will trigger ReachedEnd
  218.             if (ss.VerticalOffset + ((desiredOffset - ss.VerticalOffset) * 3) >= ss.ExtentHeight - ss.ViewportHeight)
  219.             {
  220.                 if (ReachedBottom != null)
  221.                     ReachedBottom(this, null);
  222.             }
  223.         }
  224.  
  225.         public void ScrollToIndex(int idx)
  226.         {
  227.             if (ss == null)
  228.                 return;
  229.             FrameworkElement item = (FrameworkElement)List.ItemContainerGenerator.ContainerFromIndex(idx);
  230.             if (item != null)
  231.                 ScrollToItem(item);
  232.         }
  233.  
  234.         public void ScrollToTop()
  235.         {
  236.             if (ss == null)
  237.                 return;
  238.             if (ss.VerticalOffset == 0)
  239.             {
  240.                 List.SelectedIndex = 0;
  241.                 scrollAnim_Completed(null, null);
  242.             }
  243.             else
  244.             {
  245.                 List.InvalidateArrange();
  246.                 List.InvalidateVisual();
  247.                 List.InvalidateMeasure();
  248.                 List.UpdateLayout();
  249.                 DoubleAnimation scrollAnim = new DoubleAnimation();
  250.                 scrollAnim.From = ss.VerticalOffset;
  251.                 scrollAnim.To = 0;
  252.                 scrollAnim.Duration = new Duration(TimeSpan.FromSeconds(SnapSpeed));
  253.                 scrollAnim.Completed += new EventHandler(scrollAnim_Completed);
  254.                 Mediator.BeginAnimation(ScrollViewerOffsetMediator.VerticalOffsetProperty, scrollAnim);
  255.                 List.SelectedIndex = 0;
  256.                 //ScrollToIndex(0);
  257.             }
  258.         }
  259.  
  260.         void scrollAnim_Completed(object sender, EventArgs e)
  261.         {
  262.             Dispatcher.BeginInvoke(DispatcherPriority.Input,
  263.                 new Action(delegate() { ScrollToIndex(0); }));
  264.         }
  265.  
  266.         void OnCleanupTimer(object sender, EventArgs e)
  267.         {
  268.             if (!coasting)
  269.             {
  270.                 if (List.SelectedIndex >= 0)
  271.                     ScrollToIndex(List.SelectedIndex);
  272.                 else
  273.                     ManipCompleted(null, null);
  274.             }
  275.         }
  276.         public void JumpToItem(FrameworkElement centerItem)
  277.         {
  278.             if (centerItem == null)
  279.                 return;
  280.  
  281.             double center = ss.ViewportHeight * CustomCenter;
  282.             FrameworkElement window = RelativeParent == null ? Window.GetWindow(this) : RelativeParent;
  283.  
  284.             Point itemPosition = centerItem.TransformToAncestor(window).Transform(new Point(0, 0));
  285.  
  286.             double desiredOffset = ss.VerticalOffset - (center - itemPosition.Y) + (centerItem.ActualHeight / 2);
  287.  
  288.             ss.ScrollToVerticalOffset(desiredOffset);
  289.  
  290.             SurfaceListBoxItem li = (SurfaceListBoxItem)centerItem;
  291.             li.IsSelected = true;
  292.         }
  293.  
  294.         public void JumpToIndex(int idx)
  295.         {
  296.             FrameworkElement item = (FrameworkElement)List.ItemContainerGenerator.ContainerFromIndex(idx);
  297.             if (item != null)
  298.                 JumpToItem(item);
  299.         }
  300.  
  301.         public static T GetVisualAncestor<T>(DependencyObject descendent) where T : class
  302.         {
  303.             T ancestor = null;
  304.             DependencyObject scan = descendent;
  305.  
  306.             while (scan != null && ((ancestor = scan as T) == null))
  307.             {
  308.                 scan = VisualTreeHelper.GetParent(scan);
  309.             }
  310.             return ancestor;
  311.         }
  312.  
  313.         private void ListItem_Selected(object sender, RoutedEventArgs e)
  314.         {
  315.             ScrollToItem(sender as SurfaceListBoxItem);
  316.         }
  317.  
  318.         public DependencyObject GetContainer(object item)
  319.         {
  320.             return List.ItemContainerGenerator.ContainerFromItem(item);
  321.         }
  322.     }
  323. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement