You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

778 lines
27 KiB

  1. using BPA.UIControl.Commons.KnownBoxes;
  2. using System;
  3. using System.Collections;
  4. using System.Linq;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Controls.Primitives;
  8. using System.Windows.Input;
  9. using System.Windows.Media.Animation;
  10. using System.Windows.Threading;
  11. namespace BPA.UIControl
  12. {
  13. /// <summary>
  14. /// 滑动视图
  15. /// </summary>
  16. [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(FlipViewItem))]
  17. [TemplatePart(Name = LeftButtonName, Type = typeof(Button))]
  18. [TemplatePart(Name = RightButtonName, Type = typeof(Button))]
  19. [TemplatePart(Name = UpButtonName, Type = typeof(Button))]
  20. [TemplatePart(Name = DownButtonName, Type = typeof(Button))]
  21. [TemplatePart(Name = ContentScrollViewerName, Type = typeof(ScrollViewer))]
  22. public class FlipView : ListBox
  23. {
  24. const string LeftButtonName = "PART_LeftButton";
  25. const string RightButtonName = "PART_RightButton";
  26. const string UpButtonName = "PART_UpButton";
  27. const string DownButtonName = "PART_DownButton";
  28. const string ContentScrollViewerName = "PART_ContentScrollViewer";
  29. private ScrollViewer scrollViewer;
  30. private DispatcherTimer timer;
  31. Storyboard horizontalStoryboard;
  32. Storyboard verticalStoryboard;
  33. private bool horizontalAnimating;
  34. private bool verticalAnimating;
  35. private bool sorting;
  36. private TouchPoint firstPoint;
  37. static FlipView()
  38. {
  39. DefaultStyleKeyProperty.OverrideMetadata(typeof(FlipView), new FrameworkPropertyMetadata(typeof(FlipView)));
  40. }
  41. /// <inheritdoc/>
  42. protected override bool IsItemItsOwnContainerOverride(object item)
  43. {
  44. return item is FlipViewItem;
  45. }
  46. /// <inheritdoc/>
  47. protected override DependencyObject GetContainerForItemOverride()
  48. {
  49. return new FlipViewItem();
  50. }
  51. /// <inheritdoc/>
  52. public override void OnApplyTemplate()
  53. {
  54. base.OnApplyTemplate();
  55. if (GetTemplateChild(LeftButtonName) is ButtonBase leftButton)
  56. {
  57. leftButton.Click += ClickLastItem;
  58. }
  59. if (GetTemplateChild(RightButtonName) is ButtonBase rightButton)
  60. {
  61. rightButton.Click += ClickNextItem;
  62. }
  63. if (GetTemplateChild(UpButtonName) is ButtonBase upButton)
  64. {
  65. upButton.Click += ClickLastItem;
  66. }
  67. if (GetTemplateChild(DownButtonName) is ButtonBase downButton)
  68. {
  69. downButton.Click += ClickNextItem;
  70. }
  71. scrollViewer = GetTemplateChild(ContentScrollViewerName) as ScrollViewer;
  72. scrollViewer.SizeChanged += ScrollViewer_SizeChanged;
  73. timer = new DispatcherTimer();
  74. timer.Interval = AutoPlayInterval;
  75. timer.Tick += Timer_Tick;
  76. if (IsAutoPlay)
  77. {
  78. timer.Start();
  79. }
  80. PreviewMouseWheel += FlipView_PreviewMouseWheel;
  81. PreviewTouchDown += FlipView_PreviewTouchDown;
  82. PreviewTouchMove += FlipView_PreviewTouchMove;
  83. Loaded += FlipView_Loaded;
  84. UpdateItemSort(this);
  85. horizontalStoryboard = new Storyboard();
  86. horizontalStoryboard.Completed += (sender, e) =>
  87. {
  88. var state = horizontalStoryboard.GetCurrentState(this);
  89. if (state != ClockState.Active)
  90. {
  91. horizontalAnimating = false;
  92. var horizontalOffset = HorizontalOffset;
  93. BeginAnimation(HorizontalOffsetProperty, null);
  94. HorizontalOffset = horizontalOffset;
  95. UpdateItemSort(this);
  96. }
  97. };
  98. verticalStoryboard = new Storyboard();
  99. verticalStoryboard.Completed += (sender, e) =>
  100. {
  101. var state = verticalStoryboard.GetCurrentState(this);
  102. if (state != ClockState.Active)
  103. {
  104. verticalAnimating = false;
  105. var verticalOffset = VerticalOffset;
  106. BeginAnimation(VerticalOffsetProperty, null);
  107. VerticalOffset = verticalOffset;
  108. UpdateItemSort(this);
  109. }
  110. };
  111. }
  112. private void FlipView_Loaded(object sender, RoutedEventArgs e)
  113. {
  114. ScrollSelectedItemToCenter(this, noAnimation: true);
  115. }
  116. #region properties
  117. /// <summary>
  118. /// 箭头按钮样式
  119. /// </summary>
  120. public static readonly DependencyProperty ArrowButtonStyleProperty =
  121. DependencyProperty.Register("ArrowButtonStyle", typeof(Style), typeof(FlipView), new PropertyMetadata(default(Style)));
  122. /// <summary>
  123. /// 箭头按钮样式
  124. /// </summary>
  125. public Style ArrowButtonStyle
  126. {
  127. get { return (Style)GetValue(ArrowButtonStyleProperty); }
  128. set { SetValue(ArrowButtonStyleProperty, value); }
  129. }
  130. /// <summary>
  131. /// 方向
  132. /// </summary>
  133. public static readonly DependencyProperty OrientationProperty =
  134. DependencyProperty.Register("Orientation", typeof(Orientation), typeof(FlipView), new PropertyMetadata(default(Orientation)));
  135. /// <summary>
  136. /// 方向
  137. /// </summary>
  138. public Orientation Orientation
  139. {
  140. get { return (Orientation)GetValue(OrientationProperty); }
  141. set { SetValue(OrientationProperty, value); }
  142. }
  143. /// <summary>
  144. /// 垂直偏移
  145. /// </summary>
  146. public static readonly DependencyProperty VerticalOffsetProperty =
  147. DependencyProperty.Register("VerticalOffset", typeof(double), typeof(FlipView), new PropertyMetadata(default(double)));
  148. /// <summary>
  149. /// 垂直偏移
  150. /// </summary>
  151. public double VerticalOffset
  152. {
  153. get { return (double)GetValue(VerticalOffsetProperty); }
  154. set { SetValue(VerticalOffsetProperty, value); }
  155. }
  156. /// <summary>
  157. /// 水平偏移
  158. /// </summary>
  159. public static readonly DependencyProperty HorizontalOffsetProperty =
  160. DependencyProperty.Register("HorizontalOffset", typeof(double), typeof(FlipView), new PropertyMetadata(default(double)));
  161. /// <summary>
  162. /// 水平偏移
  163. /// </summary>
  164. public double HorizontalOffset
  165. {
  166. get { return (double)GetValue(HorizontalOffsetProperty); }
  167. set { SetValue(HorizontalOffsetProperty, value); }
  168. }
  169. /// <summary>
  170. /// 动画时长
  171. /// </summary>
  172. public static readonly DependencyProperty AnimateDurationProperty =
  173. DependencyProperty.Register("AnimateDuration", typeof(Duration), typeof(FlipView), new PropertyMetadata(default(Duration)));
  174. /// <summary>
  175. /// 动画时长
  176. /// </summary>
  177. public Duration AnimateDuration
  178. {
  179. get { return (Duration)GetValue(AnimateDurationProperty); }
  180. set { SetValue(AnimateDurationProperty, value); }
  181. }
  182. /// <summary>
  183. /// 动画缓动函数
  184. /// </summary>
  185. public static readonly DependencyProperty AnimateEasingFunctionProperty =
  186. DependencyProperty.Register("AnimateEasingFunction", typeof(IEasingFunction), typeof(FlipView), new PropertyMetadata(default(IEasingFunction)));
  187. /// <summary>
  188. /// 动画缓动函数
  189. /// </summary>
  190. public IEasingFunction AnimateEasingFunction
  191. {
  192. get { return (IEasingFunction)GetValue(AnimateEasingFunctionProperty); }
  193. set { SetValue(AnimateEasingFunctionProperty, value); }
  194. }
  195. /// <summary>
  196. /// 是否按钮浮动
  197. /// </summary>
  198. public static readonly DependencyProperty IsButtonFloatProperty =
  199. DependencyProperty.Register("IsButtonFloat", typeof(bool), typeof(FlipView), new PropertyMetadata(BooleanBoxes.TrueBox, OnIsButtonFloatChanged));
  200. /// <summary>
  201. /// 是否按钮浮动
  202. /// </summary>
  203. public bool IsButtonFloat
  204. {
  205. get { return (bool)GetValue(IsButtonFloatProperty); }
  206. set { SetValue(IsButtonFloatProperty, BooleanBoxes.Box(value)); }
  207. }
  208. /// <summary>
  209. /// 是否循环
  210. /// </summary>
  211. public static readonly DependencyProperty IsLoopProperty =
  212. DependencyProperty.Register("IsLoop", typeof(bool), typeof(FlipView), new PropertyMetadata(BooleanBoxes.FalseBox, OnIsLoopChanged));
  213. /// <summary>
  214. /// 是否循环
  215. /// </summary>
  216. public bool IsLoop
  217. {
  218. get { return (bool)GetValue(IsLoopProperty); }
  219. set { SetValue(IsLoopProperty, BooleanBoxes.Box(value)); }
  220. }
  221. /// <summary>
  222. /// 自动播放
  223. /// </summary>
  224. public static readonly DependencyProperty IsAutoPlayProperty =
  225. DependencyProperty.Register("IsAutoPlay", typeof(bool), typeof(FlipView), new PropertyMetadata(BooleanBoxes.FalseBox, OnIsAutoPlayChanged));
  226. /// <summary>
  227. /// 自动播放
  228. /// </summary>
  229. public bool IsAutoPlay
  230. {
  231. get { return (bool)GetValue(IsAutoPlayProperty); }
  232. set { SetValue(IsAutoPlayProperty, BooleanBoxes.Box(value)); }
  233. }
  234. /// <summary>
  235. /// 是否滚动鼠标
  236. /// </summary>
  237. public static readonly DependencyProperty IsMouseWheelProperty =
  238. DependencyProperty.Register("IsMouseWheel", typeof(bool), typeof(FlipView), new PropertyMetadata(BooleanBoxes.TrueBox));
  239. /// <summary>
  240. /// 是否滚动鼠标
  241. /// </summary>
  242. public bool IsMouseWheel
  243. {
  244. get { return (bool)GetValue(IsMouseWheelProperty); }
  245. set { SetValue(IsMouseWheelProperty, BooleanBoxes.Box(value)); }
  246. }
  247. /// <summary>
  248. /// 播放间隔
  249. /// </summary>
  250. public static readonly DependencyProperty AutoPlayIntervalProperty =
  251. DependencyProperty.Register("AutoPlayInterval", typeof(TimeSpan), typeof(FlipView), new PropertyMetadata(TimeSpan.FromSeconds(3), OnAutoPlayIntervalChanged));
  252. /// <summary>
  253. /// 播放间隔
  254. /// </summary>
  255. public TimeSpan AutoPlayInterval
  256. {
  257. get { return (TimeSpan)GetValue(AutoPlayIntervalProperty); }
  258. set { SetValue(AutoPlayIntervalProperty, value); }
  259. }
  260. /// <summary>
  261. /// 是否连续切换
  262. /// </summary>
  263. public static readonly DependencyProperty IsContinuousSwitchingProperty =
  264. DependencyProperty.Register("IsContinuousSwitching", typeof(bool), typeof(FlipView), new PropertyMetadata(BooleanBoxes.FalseBox));
  265. /// <summary>
  266. /// 是否连续切换
  267. /// </summary>
  268. public bool IsContinuousSwitching
  269. {
  270. get { return (bool)GetValue(IsContinuousSwitchingProperty); }
  271. set { SetValue(IsContinuousSwitchingProperty, BooleanBoxes.Box(value)); }
  272. }
  273. #endregion
  274. private void RestartTimer()
  275. {
  276. timer.Stop();
  277. if (IsAutoPlay)
  278. {
  279. timer.Start();
  280. }
  281. }
  282. /// <inheritdoc/>
  283. protected override void OnSelectionChanged(SelectionChangedEventArgs e)
  284. {
  285. base.OnSelectionChanged(e);
  286. if (IsLoaded && !sorting && SelectedIndex >= 0)
  287. {
  288. RestartTimer();
  289. ScrollSelectedItemToCenter(this);
  290. }
  291. if (SelectedIndex < 0 && Items.Count > 0)
  292. {
  293. SelectedIndex = 0;
  294. }
  295. }
  296. /// <summary>
  297. /// 是否禁止切换 item
  298. /// </summary>
  299. private static bool IsForbidSwitching(FlipView flipView)
  300. {
  301. return (flipView.horizontalAnimating || flipView.verticalAnimating) && !flipView.IsContinuousSwitching;
  302. }
  303. /// <inheritdoc/>
  304. protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
  305. {
  306. if (IsForbidSwitching(this))
  307. {
  308. e.Handled = true;
  309. return;
  310. }
  311. }
  312. /// <inheritdoc/>
  313. protected override void OnPreviewMouseMove(MouseEventArgs e)
  314. {
  315. if (IsForbidSwitching(this))
  316. {
  317. ReleaseMouseCapture();
  318. e.Handled = true;
  319. return;
  320. }
  321. }
  322. /// <inheritdoc/>
  323. protected override void OnPreviewKeyDown(KeyEventArgs e)
  324. {
  325. if (IsForbidSwitching(this))
  326. {
  327. e.Handled = true;
  328. return;
  329. }
  330. }
  331. /// <summary>
  332. /// 开始滚动偏移动画
  333. /// </summary>
  334. /// <param name="flipView">滑动视图</param>
  335. /// <param name="offset">偏移</param>
  336. private static void StartOffsetAnimation(FlipView flipView, double offset)
  337. {
  338. if (flipView.Orientation == Orientation.Horizontal && flipView.HorizontalOffset != offset)
  339. {
  340. HorizontalAnimation(flipView, offset, flipView.AnimateDuration);
  341. }
  342. else if (flipView.Orientation == Orientation.Vertical && flipView.VerticalOffset != offset)
  343. {
  344. VerticalAnimation(flipView, offset, flipView.AnimateDuration);
  345. }
  346. }
  347. /// <summary>
  348. /// 改变滚动偏移
  349. /// </summary>
  350. /// <param name="flipView">滑动视图</param>
  351. /// <param name="offset">偏移</param>
  352. private static void ChangeOffset(FlipView flipView, double offset)
  353. {
  354. if (flipView.Orientation == Orientation.Horizontal && flipView.scrollViewer.HorizontalOffset != offset)
  355. {
  356. flipView.HorizontalOffset = offset;
  357. }
  358. else if (flipView.Orientation == Orientation.Vertical && flipView.scrollViewer.VerticalOffset != offset)
  359. {
  360. flipView.VerticalOffset = offset;
  361. }
  362. }
  363. /// <summary>
  364. /// 获取当前偏移
  365. /// </summary>
  366. /// <param name="item">子项</param>
  367. /// <param name="orientation">方向</param>
  368. /// <param name="scrollViewer">滚动视图</param>
  369. /// <returns>偏移</returns>
  370. private static double GetCurrentOffset(FlipViewItem item, Orientation orientation, ScrollViewer scrollViewer)
  371. {
  372. var point = new Point(scrollViewer.HorizontalOffset, scrollViewer.VerticalOffset);
  373. var targetPosition = item.TransformToVisual(scrollViewer).Transform(point);
  374. if (orientation == Orientation.Horizontal)
  375. {
  376. return targetPosition.X - (scrollViewer.ViewportWidth - item.ActualWidth) / 2;
  377. }
  378. else
  379. {
  380. return targetPosition.Y - (scrollViewer.ViewportHeight - item.ActualHeight) / 2;
  381. }
  382. }
  383. /// <summary>
  384. /// 滚动到当前子项
  385. /// </summary>
  386. /// <param name="flipView">滑动视图</param>
  387. /// <param name="noAnimation">不使用动画</param>
  388. private static void ScrollSelectedItemToCenter(FlipView flipView, bool noAnimation = false)
  389. {
  390. if (!flipView.IsLoaded || flipView.SelectedIndex < 0 || IsForbidSwitching(flipView))
  391. {
  392. return;
  393. }
  394. var item = flipView.ItemContainerGenerator.ContainerFromIndex(flipView.SelectedIndex) as FlipViewItem;
  395. var offset = GetCurrentOffset(item, flipView.Orientation, flipView.scrollViewer);
  396. if (noAnimation)
  397. {
  398. ChangeOffset(flipView, offset);
  399. }
  400. else
  401. {
  402. StartOffsetAnimation(flipView, offset);
  403. }
  404. }
  405. /// <summary>
  406. /// 更新子项排序
  407. /// </summary>
  408. private static void UpdateItemSort(FlipView flipView)
  409. {
  410. flipView.sorting = true;
  411. var count = flipView.Items.Count;
  412. if (flipView.Items.Count > 0)
  413. {
  414. if (flipView.SelectedIndex < 0)
  415. {
  416. flipView.SelectedIndex = 0;
  417. }
  418. if (flipView.IsLoop)
  419. {
  420. int frontCount = (count - 1) / 2; // 当前选中项前面应该有多少个
  421. int index = flipView.Items.IndexOf(flipView.SelectedItem);
  422. if (index < frontCount) // 需要向前补 item
  423. {
  424. index = flipView.Items.IndexOf(flipView.SelectedItem);
  425. int num = frontCount - index; // 补 item 数量
  426. while (num-- > 0)
  427. {
  428. var item = flipView.Items[count - 1];
  429. if (flipView.ItemContainerGenerator.ContainerFromItem(item) is FlipViewItem flipViewItem)
  430. {
  431. var offset = flipView.Orientation == Orientation.Horizontal ?
  432. flipView.HorizontalOffset + flipViewItem.ActualWidth :
  433. flipView.VerticalOffset + flipViewItem.ActualHeight;
  434. if (flipView.IsLoaded)
  435. {
  436. ChangeOffset(flipView, offset);
  437. }
  438. }
  439. if (flipView.ItemsSource is IList list)
  440. {
  441. list.Remove(item);
  442. list.Insert(0, item);
  443. }
  444. else
  445. {
  446. flipView.Items.Remove(item);
  447. flipView.Items.Insert(0, item);
  448. }
  449. }
  450. }
  451. else if (index > frontCount) // 需要向后补 item
  452. {
  453. int num = index - frontCount; // 补 item 数量
  454. while (num-- > 0)
  455. {
  456. var item = flipView.Items[0];
  457. if (flipView.ItemContainerGenerator.ContainerFromItem(item) is FlipViewItem flipViewItem)
  458. {
  459. var offset = flipView.Orientation == Orientation.Horizontal ?
  460. flipView.HorizontalOffset - flipViewItem.ActualWidth :
  461. flipView.VerticalOffset - flipViewItem.ActualHeight;
  462. if (flipView.IsLoaded)
  463. {
  464. ChangeOffset(flipView, offset);
  465. }
  466. }
  467. if (flipView.ItemsSource is IList list)
  468. {
  469. list.Remove(item);
  470. list.Insert(count - 1, item);
  471. }
  472. else
  473. {
  474. flipView.Items.Remove(item);
  475. flipView.Items.Insert(count - 1, item);
  476. }
  477. }
  478. }
  479. flipView.UpdateLayout();
  480. ScrollSelectedItemToCenter(flipView, noAnimation: true);
  481. }
  482. }
  483. flipView.sorting = false;
  484. }
  485. /// <summary>
  486. /// 下一张
  487. /// </summary>
  488. private void ClickNextItem(object sender, RoutedEventArgs e)
  489. {
  490. if (IsForbidSwitching(this) || SelectedIndex >= Items.Count - 1)
  491. {
  492. return;
  493. }
  494. SelectedIndex++;
  495. }
  496. /// <summary>
  497. /// 上一张
  498. /// </summary>
  499. private void ClickLastItem(object sender, RoutedEventArgs e)
  500. {
  501. if (IsForbidSwitching(this) || SelectedIndex <= 0)
  502. {
  503. return;
  504. }
  505. SelectedIndex--;
  506. }
  507. /// <summary>
  508. /// 水平动画
  509. /// </summary>
  510. /// <param name="flipView">滑动视图</param>
  511. /// <param name="offset">偏移</param>
  512. /// <param name="duration">动画时长</param>
  513. private static void HorizontalAnimation(FlipView flipView, double offset, Duration duration)
  514. {
  515. if (offset < 0)
  516. {
  517. offset = 0;
  518. }
  519. else if (offset > flipView.scrollViewer.ScrollableWidth)
  520. {
  521. offset = flipView.scrollViewer.ScrollableWidth;
  522. }
  523. DoubleAnimation animation = flipView.horizontalStoryboard.Children.Count > 0 ?
  524. flipView.horizontalStoryboard.Children[0] as DoubleAnimation :
  525. new DoubleAnimation();
  526. animation.From = flipView.HorizontalOffset;
  527. animation.To = offset;
  528. animation.Duration = duration;
  529. animation.EasingFunction = flipView.AnimateEasingFunction;
  530. Storyboard.SetTargetProperty(animation, new PropertyPath(HorizontalOffsetProperty));
  531. Storyboard.SetTarget(animation, flipView);
  532. if (flipView.horizontalStoryboard.Children.Count == 0)
  533. {
  534. flipView.horizontalStoryboard.Children.Add(animation);
  535. }
  536. flipView.horizontalAnimating = true;
  537. flipView.horizontalStoryboard.Begin(flipView, isControllable: true);
  538. }
  539. /// <summary>
  540. /// 垂直动画
  541. /// </summary>
  542. /// <param name="flipView">滑动视图</param>
  543. /// <param name="offset">偏移</param>
  544. /// <param name="duration">动画时长</param>
  545. private static void VerticalAnimation(FlipView flipView, double offset, Duration duration)
  546. {
  547. if (offset < 0)
  548. {
  549. offset = 0;
  550. }
  551. else if (offset > flipView.scrollViewer.ScrollableHeight)
  552. {
  553. offset = flipView.scrollViewer.ScrollableHeight;
  554. }
  555. DoubleAnimation animation = flipView.verticalStoryboard.Children.Count > 0 ?
  556. flipView.verticalStoryboard.Children[0] as DoubleAnimation :
  557. new DoubleAnimation();
  558. animation.From = flipView.VerticalOffset;
  559. animation.To = offset;
  560. animation.Duration = flipView.AnimateDuration;
  561. animation.EasingFunction = flipView.AnimateEasingFunction;
  562. Storyboard.SetTargetProperty(animation, new PropertyPath(VerticalOffsetProperty));
  563. Storyboard.SetTarget(animation, flipView);
  564. if (flipView.verticalStoryboard.Children.Count == 0)
  565. {
  566. flipView.verticalStoryboard.Children.Add(animation);
  567. }
  568. flipView.verticalAnimating = true;
  569. flipView.verticalStoryboard.Begin(flipView, isControllable: true);
  570. }
  571. private static void OnIsLoopChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  572. {
  573. if ((bool)e.NewValue)
  574. {
  575. UpdateItemSort(d as FlipView);
  576. }
  577. }
  578. private static void OnIsButtonFloatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  579. {
  580. var flipView = d as FlipView;
  581. if (!flipView.IsLoaded)
  582. {
  583. return;
  584. }
  585. ScrollSelectedItemToCenter(flipView);
  586. }
  587. /// <summary>
  588. /// 定时触发翻页
  589. /// </summary>
  590. private void Timer_Tick(object sender, EventArgs e)
  591. {
  592. ClickNextItem(this, null);
  593. }
  594. /// <summary>
  595. /// 是否自动播放改变
  596. /// </summary>
  597. private static void OnIsAutoPlayChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  598. {
  599. var flipView = d as FlipView;
  600. if (flipView.IsAutoPlay)
  601. {
  602. flipView.timer?.Start();
  603. }
  604. else
  605. {
  606. flipView.timer.Stop();
  607. }
  608. }
  609. /// <summary>
  610. /// 自动播放间隔改变
  611. /// </summary>
  612. private static void OnAutoPlayIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  613. {
  614. var flipView = d as FlipView;
  615. flipView.timer.Interval = flipView.AutoPlayInterval;
  616. }
  617. /// <summary>
  618. /// 滚动鼠标翻页
  619. /// </summary>
  620. private void FlipView_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
  621. {
  622. e.Handled = true;
  623. if (!IsMouseWheel)
  624. {
  625. return;
  626. }
  627. if (e.Delta > 0)
  628. {
  629. ClickLastItem(null, null);
  630. }
  631. else
  632. {
  633. ClickNextItem(null, null);
  634. }
  635. }
  636. private void FlipView_PreviewTouchDown(object sender, TouchEventArgs e)
  637. {
  638. e.Handled = true;
  639. firstPoint = e.GetTouchPoint(this);
  640. }
  641. private void FlipView_PreviewTouchMove(object sender, TouchEventArgs e)
  642. {
  643. if (!IsMouseWheel || firstPoint is null)
  644. {
  645. return;
  646. }
  647. var lastPoint = e.GetTouchPoint(this);
  648. double offset;
  649. if (this.Orientation == Orientation.Horizontal)
  650. {
  651. offset = lastPoint.Position.X - firstPoint.Position.X;
  652. }
  653. else
  654. {
  655. offset = lastPoint.Position.Y - firstPoint.Position.Y;
  656. }
  657. if (offset > 30)
  658. {
  659. firstPoint = lastPoint;
  660. ClickLastItem(null, null);
  661. }
  662. else if (offset < -30)
  663. {
  664. firstPoint = lastPoint;
  665. ClickNextItem(null, null);
  666. }
  667. }
  668. /// <summary>
  669. /// 滚动区域大小变化
  670. /// </summary>
  671. private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
  672. {
  673. if (SelectedIndex < 0 || IsForbidSwitching(this) ||
  674. !(ItemContainerGenerator.ContainerFromIndex(SelectedIndex) is FlipViewItem item))
  675. {
  676. return;
  677. }
  678. var offset = GetCurrentOffset(item, Orientation, scrollViewer);
  679. ChangeOffset(this, offset);
  680. }
  681. }
  682. }