Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Navigation;
- using System.Windows.Shapes;
- using Microsoft.Surface.Presentation.Controls;
- using System.Windows.Media.Animation;
- using System.Collections.Specialized;
- using System.Collections;
- using System.Windows.Threading;
- using System.Timers;
- namespace ATypeSurfaceControls
- {
- /// <summary>
- /// Interaction logic for SnapList.xaml
- /// </summary>
- public partial class SnapList : UserControl
- {
- const double VERTICAL_TAKEOVER_TOLERANCE = 15;
- SurfaceScrollViewer ss;
- private bool coasting;
- #region dependency properties
- #region item properties
- public IEnumerable ItemsSource
- {
- get { return (IEnumerable)GetValue(ItemsSourceProperty); }
- set { SetValue(ItemsSourceProperty, value); }
- }
- public static readonly DependencyProperty ItemsSourceProperty =
- DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(SnapList), new PropertyMetadata(null));
- public DataTemplate ItemContentTemplate
- {
- get { return (DataTemplate)GetValue(ItemContentTemplateProperty); }
- set { SetValue(ItemContentTemplateProperty, value); }
- }
- public static readonly DependencyProperty ItemContentTemplateProperty =
- DependencyProperty.Register("ItemContentTemplate", typeof(DataTemplate), typeof(SnapList), new UIPropertyMetadata(null));
- public ControlTemplate ItemTemplate
- {
- get { return (ControlTemplate)GetValue(ItemTemplateProperty); }
- set { SetValue(ItemTemplateProperty, value); }
- }
- public static readonly DependencyProperty ItemTemplateProperty =
- DependencyProperty.Register("ItemTemplate", typeof(ControlTemplate), typeof(SnapList), new UIPropertyMetadata(null));
- #endregion
- #region behavior
- public double SnapSpeed
- {
- get { return (double)GetValue(SnapSpeedProperty); }
- set { SetValue(SnapSpeedProperty, value); }
- }
- // Using a DependencyProperty as the backing store for SnapSpeed. This enables animation, styling, binding, etc...
- public static readonly DependencyProperty SnapSpeedProperty =
- DependencyProperty.Register("SnapSpeed", typeof(double), typeof(SnapList), new UIPropertyMetadata(0.1));
- /// <summary>
- /// 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.
- /// </summary>
- public FrameworkElement RelativeParent
- {
- get { return (FrameworkElement)GetValue(RelativeParentProperty); }
- set { SetValue(RelativeParentProperty, value); }
- }
- // Using a DependencyProperty as the backing store for RelativeParent. This enables animation, styling, binding, etc...
- public static readonly DependencyProperty RelativeParentProperty =
- DependencyProperty.Register("RelativeParent", typeof(FrameworkElement), typeof(SnapList), new UIPropertyMetadata(null));
- /// <summary>
- /// A custom-defined center point for the list to snap to.
- /// </summary>
- public double CustomCenter
- {
- get { return (double)GetValue(CustomCenterProperty); }
- set { SetValue(CustomCenterProperty, value); }
- }
- // Using a DependencyProperty as the backing store for CustomCenter. This enables animation, styling, binding, etc...
- public static readonly DependencyProperty CustomCenterProperty =
- DependencyProperty.Register("CustomCenter", typeof(double), typeof(SnapList), new UIPropertyMetadata(0.5));
- #endregion
- #endregion
- #region events
- public event SelectionChangedEventHandler SelectionChanged;
- public event EventHandler ReachedBottom;
- #endregion
- public SnapList()
- {
- InitializeComponent();
- Loaded += new RoutedEventHandler(SnapList_Loaded);
- }
- void SnapList_Loaded(object sender, RoutedEventArgs e)
- {
- ss = VisualTreeHelper.GetChild(List, 0) as SurfaceScrollViewer;
- Mediator.ScrollViewer = ss;
- List.SelectionMode = SelectionMode.Single;
- ss.ScrollChanged += new ScrollChangedEventHandler(ss_ScrollChanged);
- AddHandler(SurfaceScrollViewer.ManipulationCompletedEvent, new EventHandler<ManipulationCompletedEventArgs>(ManipCompleted), true);
- AddHandler(SurfaceScrollViewer.ManipulationStartingEvent, new EventHandler<ManipulationStartingEventArgs>(ManipStarting), true);
- List.SelectionChanged += new SelectionChangedEventHandler(List_SelectionChanged);
- if (List.HasItems)
- ScrollToIndex(0);
- DispatcherTimer cleanup = new DispatcherTimer(TimeSpan.FromSeconds(1), DispatcherPriority.Background, new EventHandler(OnCleanupTimer), Dispatcher);
- cleanup.Start();
- }
- void ss_ScrollChanged(object sender, ScrollChangedEventArgs e)
- {
- if (List.HasItems && e.VerticalOffset + e.VerticalChange >= ss.ExtentHeight - ss.ViewportHeight)
- {
- if (ReachedBottom != null)
- ReachedBottom(this, null);
- }
- }
- void List_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- if (this.SelectionChanged != null)
- {
- this.SelectionChanged(this, e);
- }
- }
- void ManipStarting(object sender, ManipulationStartingEventArgs e)
- {
- coasting = true;
- }
- void ManipCompleted(object sender, ManipulationCompletedEventArgs e)
- {
- coasting = false;
- List<FrameworkElement> visibleElements = new List<FrameworkElement>();
- for (int i = 0; i < List.Items.Count; i++)
- {
- SurfaceListBoxItem item = List.ItemContainerGenerator.ContainerFromIndex(i) as SurfaceListBoxItem;
- if (ViewportHelper.IsInViewport(item))
- {
- FrameworkElement el = item as FrameworkElement;
- visibleElements.Add(el);
- }
- }
- FrameworkElement window = RelativeParent == null ? List : RelativeParent;
- double center = ss.ViewportHeight * CustomCenter;
- double closestCenterOffset = double.MaxValue;
- FrameworkElement centerItem = visibleElements.Count > 0 ? visibleElements[0] :
- List.ItemContainerGenerator.ContainerFromIndex(1) as FrameworkElement;
- foreach (FrameworkElement el in visibleElements)
- {
- double centerOffset = Math.Abs(el.TransformToAncestor(window).Transform(new Point(0, 0)).Y + (el.ActualHeight / 2) - center);
- if (centerOffset < closestCenterOffset)
- {
- closestCenterOffset = centerOffset;
- centerItem = el;
- }
- }
- ScrollToItem(centerItem);
- }
- public void ScrollToItem(FrameworkElement centerItem)
- {
- if (centerItem == null)
- return;
- if (ss == null)
- return;
- double center = ss.ViewportHeight * CustomCenter;
- FrameworkElement window = RelativeParent == null ? Window.GetWindow(this) : RelativeParent;
- Point itemPosition = centerItem.TransformToAncestor(window).Transform(new Point(0, 0));
- double desiredOffset = ss.VerticalOffset - (center - itemPosition.Y) + (centerItem.ActualHeight / 2);
- DoubleAnimation scrollAnim = new DoubleAnimation();
- scrollAnim.From = ss.VerticalOffset;
- scrollAnim.To = desiredOffset;
- scrollAnim.Duration = new Duration(TimeSpan.FromSeconds(SnapSpeed));
- Mediator.BeginAnimation(ScrollViewerOffsetMediator.VerticalOffsetProperty, scrollAnim);
- SurfaceListBoxItem li = (SurfaceListBoxItem)centerItem;
- //List.SelectedItem = li;
- li.IsSelected = true;
- //check if scroll will trigger ReachedEnd
- if (ss.VerticalOffset + ((desiredOffset - ss.VerticalOffset) * 3) >= ss.ExtentHeight - ss.ViewportHeight)
- {
- if (ReachedBottom != null)
- ReachedBottom(this, null);
- }
- }
- public void ScrollToIndex(int idx)
- {
- if (ss == null)
- return;
- FrameworkElement item = (FrameworkElement)List.ItemContainerGenerator.ContainerFromIndex(idx);
- if (item != null)
- ScrollToItem(item);
- }
- public void ScrollToTop()
- {
- if (ss == null)
- return;
- if (ss.VerticalOffset == 0)
- {
- List.SelectedIndex = 0;
- scrollAnim_Completed(null, null);
- }
- else
- {
- List.InvalidateArrange();
- List.InvalidateVisual();
- List.InvalidateMeasure();
- List.UpdateLayout();
- DoubleAnimation scrollAnim = new DoubleAnimation();
- scrollAnim.From = ss.VerticalOffset;
- scrollAnim.To = 0;
- scrollAnim.Duration = new Duration(TimeSpan.FromSeconds(SnapSpeed));
- scrollAnim.Completed += new EventHandler(scrollAnim_Completed);
- Mediator.BeginAnimation(ScrollViewerOffsetMediator.VerticalOffsetProperty, scrollAnim);
- List.SelectedIndex = 0;
- //ScrollToIndex(0);
- }
- }
- void scrollAnim_Completed(object sender, EventArgs e)
- {
- Dispatcher.BeginInvoke(DispatcherPriority.Input,
- new Action(delegate() { ScrollToIndex(0); }));
- }
- void OnCleanupTimer(object sender, EventArgs e)
- {
- if (!coasting)
- {
- if (List.SelectedIndex >= 0)
- ScrollToIndex(List.SelectedIndex);
- else
- ManipCompleted(null, null);
- }
- }
- public void JumpToItem(FrameworkElement centerItem)
- {
- if (centerItem == null)
- return;
- double center = ss.ViewportHeight * CustomCenter;
- FrameworkElement window = RelativeParent == null ? Window.GetWindow(this) : RelativeParent;
- Point itemPosition = centerItem.TransformToAncestor(window).Transform(new Point(0, 0));
- double desiredOffset = ss.VerticalOffset - (center - itemPosition.Y) + (centerItem.ActualHeight / 2);
- ss.ScrollToVerticalOffset(desiredOffset);
- SurfaceListBoxItem li = (SurfaceListBoxItem)centerItem;
- li.IsSelected = true;
- }
- public void JumpToIndex(int idx)
- {
- FrameworkElement item = (FrameworkElement)List.ItemContainerGenerator.ContainerFromIndex(idx);
- if (item != null)
- JumpToItem(item);
- }
- public static T GetVisualAncestor<T>(DependencyObject descendent) where T : class
- {
- T ancestor = null;
- DependencyObject scan = descendent;
- while (scan != null && ((ancestor = scan as T) == null))
- {
- scan = VisualTreeHelper.GetParent(scan);
- }
- return ancestor;
- }
- private void ListItem_Selected(object sender, RoutedEventArgs e)
- {
- ScrollToItem(sender as SurfaceListBoxItem);
- }
- public DependencyObject GetContainer(object item)
- {
- return List.ItemContainerGenerator.ContainerFromItem(item);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement