Created
May 17, 2014 04:48
-
-
Save ideaki/26e99048580fe87aa5d7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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