Skip to content

Instantly share code, notes, and snippets.

@ideaki
Created May 17, 2014 04:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ideaki/26e99048580fe87aa5d7 to your computer and use it in GitHub Desktop.
Save ideaki/26e99048580fe87aa5d7 to your computer and use it in GitHub Desktop.
using System;
using System.Linq;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
namespace ListViewAutoScroll
{
/// <summary>
/// ミドルクリックでオートスクロールができるカスタムListView
/// ※VirtualizingStackPanel専用
/// </summary>
public class MyListView : ListView
{
private ScrollViewer _sv;
private double _speed = 0;
private bool _isScrollEnabled = false;
private Point _pressedPoint;
private DispatcherTimer _dt;
private Popup AutoScrollNavigationFlyout = new Popup()
{
IsLightDismissEnabled = true,
Width = 30,
Height = 30,
Child = new AutoScrollNavigationContent()
};
/// <summary>
/// ListView内のScrollViewer
/// </summary>
public ScrollViewer SV
{
get { return _sv; }
set { _sv = value; }
}
/// <summary>
/// オートスクロールの速度
/// 1/60秒あたりにスクロールするピクセル
/// 正で下へ
/// 負で上へ
/// 0で停止
/// </summary>
public double ScrollSpeed
{
get { return _speed; }
set { _speed = value; }
}
/// <summary>
/// trueでオートスクロール開始
/// falseで停止
/// </summary>
public bool IsScrollEnabled
{
get { return _isScrollEnabled; }
set
{
_isScrollEnabled = value;
if (_isScrollEnabled) _dt.Start();
else _dt.Stop();
}
}
private int CurrentItemIndex
{
get { return (int)SV.VerticalOffset - 2; }
}
private ListViewItem CurrentItem
{
get { return this.ContainerFromIndex(CurrentItemIndex) as ListViewItem; }
}
/// <summary>
/// ListView内のScrollViewerを取り出す
/// </summary>
protected override void OnApplyTemplate()
{
ItemsSource = Enumerable.Range(1, 10000);
SV = (ScrollViewer)this.GetTemplateChild("ScrollViewer");
base.OnApplyTemplate();
}
/// <summary>
/// アイテムに色と高さを設定
/// </summary>
/// <param name="element"></param>
/// <param name="item"></param>
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
int index = IndexFromContainer(element);
if (index % 2 == 0)
{
element.SetValue(BackgroundProperty, new SolidColorBrush(Colors.Gray));
}
else
{
element.SetValue(BackgroundProperty, new SolidColorBrush(Colors.Black));
}
element.SetValue(HeightProperty, index+10);
base.PrepareContainerForItemOverride(element, item);
}
/// <summary>
/// ミドルクリックしたポジションにナビゲーションフライアウトを出現させる
/// ミドルクリックオートスクロールの開始
/// </summary>
/// <param name="e"></param>
protected override void OnPointerPressed(PointerRoutedEventArgs e)
{
if (!e.GetCurrentPoint(null).Properties.IsMiddleButtonPressed) return;
if(_dt==null)
{
_dt = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(16) };
_dt.Tick += dt_Tick;
}
AutoScrollNavigationFlyout.IsOpen = true;
_pressedPoint = e.GetCurrentPoint(null).Position;
Canvas.SetLeft(AutoScrollNavigationFlyout, _pressedPoint.X - 15);
Canvas.SetTop(AutoScrollNavigationFlyout, _pressedPoint.Y - 15);
ScrollSpeed = 0;
IsScrollEnabled = true;
AutoScrollNavigationFlyout.Closed += popup_Closed;
Window.Current.CoreWindow.PointerMoved += CoreWindow_PointerMoved;
base.OnPointerPressed(e);
}
/// <summary>
/// オートスクロールの実体
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void dt_Tick(object sender, object e)
{
SV.ChangeView(null, SV.VerticalOffset + ScrollSpeed / CurrentItem.ActualHeight, null);
SV.UpdateLayout();
}
/// <summary>
/// ポインタを監視
/// フライアウトからポインタが離れるほど早くスクロールさせる
/// ScorollSpeedの決定がいまいち
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
void CoreWindow_PointerMoved(CoreWindow sender, PointerEventArgs args)
{
var nowPt = args.CurrentPoint.Position;
var len = (int)(nowPt.Y - _pressedPoint.Y);
if (300 < Math.Abs(len))
{
ScrollSpeed = ((int)Math.Abs(len) * (int)len) / 200;
}
else if (150 < Math.Abs(len))
{
ScrollSpeed = ((int)Math.Abs(len) * (int)len) / 700;
}
else if (15 < Math.Abs(len))
{
ScrollSpeed = ((int)Math.Abs(len) / (int)len) * (Math.Abs(len) - 15) / 8.0f;
}
else
{
ScrollSpeed = 0;
}
}
/// <summary>
/// オートスクロールの停止
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void popup_Closed(object sender, object e)
{
var popup = sender as Popup;
IsScrollEnabled = false;
popup.Closed -= popup_Closed;
Window.Current.CoreWindow.PointerMoved -= CoreWindow_PointerMoved;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment