NavigationPanel.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Media;
  6. namespace CustomUI
  7. {
  8. public class NavigationPanel : ContentControl
  9. {
  10. #region private fields
  11. private SegmentControl PART_Indicator;
  12. private ContentPresenter PART_ContentPresenter;
  13. private ScrollViewer mScrollViewer;
  14. private List<ZGroupBox> mHeaderList;
  15. private double oldOffsetY;
  16. #endregion
  17. #region DependencyProperty
  18. #region ItemsSource
  19. public IEnumerable ItemsSource
  20. {
  21. get { return (IEnumerable)GetValue(ItemsSourceProperty); }
  22. private set { SetValue(ItemsSourceProperty, value); }
  23. }
  24. public static readonly DependencyProperty ItemsSourceProperty =
  25. DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(NavigationPanel));
  26. #endregion
  27. #region IndicatorStyle
  28. public Style IndicatorStyle
  29. {
  30. get { return (Style)GetValue(IndicatorStyleProperty); }
  31. set { SetValue(IndicatorStyleProperty, value); }
  32. }
  33. public static readonly DependencyProperty IndicatorStyleProperty =
  34. DependencyProperty.Register("IndicatorStyle", typeof(Style), typeof(NavigationPanel), new PropertyMetadata(null));
  35. #endregion
  36. #region IndicatorItemContainerStyle
  37. public Style IndicatorItemContainerStyle
  38. {
  39. get { return (Style)GetValue(IndicatorItemContainerStyleProperty); }
  40. set { SetValue(IndicatorItemContainerStyleProperty, value); }
  41. }
  42. public static readonly DependencyProperty IndicatorItemContainerStyleProperty =
  43. DependencyProperty.Register("IndicatorItemContainerStyle", typeof(Style), typeof(NavigationPanel), new PropertyMetadata(null));
  44. #endregion
  45. #region IndicatorItemsPanel
  46. public ItemsPanelTemplate IndicatorItemsPanel
  47. {
  48. get { return (ItemsPanelTemplate)GetValue(IndicatorItemsPanelProperty); }
  49. set { SetValue(IndicatorItemsPanelProperty, value); }
  50. }
  51. public static readonly DependencyProperty IndicatorItemsPanelProperty =
  52. DependencyProperty.Register("IndicatorItemsPanel", typeof(ItemsPanelTemplate), typeof(NavigationPanel));
  53. #endregion
  54. #region IndicatorPlacement
  55. public Dock IndicatorPlacement
  56. {
  57. get { return (Dock)GetValue(IndicatorPlacementProperty); }
  58. set { SetValue(IndicatorPlacementProperty, value); }
  59. }
  60. public static readonly DependencyProperty IndicatorPlacementProperty =
  61. DependencyProperty.Register("IndicatorPlacement", typeof(Dock), typeof(NavigationPanel), new PropertyMetadata(Dock.Top));
  62. #endregion
  63. #region IndicatorMargin
  64. public Thickness IndicatorMargin
  65. {
  66. get { return (Thickness)GetValue(IndicatorMarginProperty); }
  67. set { SetValue(IndicatorMarginProperty, value); }
  68. }
  69. public static readonly DependencyProperty IndicatorMarginProperty =
  70. DependencyProperty.Register("IndicatorMargin", typeof(Thickness), typeof(NavigationPanel));
  71. #endregion
  72. #region IndicatorHorizontalAlignment
  73. public HorizontalAlignment IndicatorHorizontalAlignment
  74. {
  75. get { return (HorizontalAlignment)GetValue(IndicatorHorizontalAlignmentProperty); }
  76. set { SetValue(IndicatorHorizontalAlignmentProperty, value); }
  77. }
  78. public static readonly DependencyProperty IndicatorHorizontalAlignmentProperty =
  79. DependencyProperty.Register("IndicatorHorizontalAlignment", typeof(HorizontalAlignment)
  80. , typeof(NavigationPanel));
  81. #endregion
  82. #region IndicatorSelectedIndex
  83. public int IndicatorSelectedIndex
  84. {
  85. get { return (int)GetValue(IndicatorSelectedIndexProperty); }
  86. set { SetValue(IndicatorSelectedIndexProperty, value); }
  87. }
  88. public static readonly DependencyProperty IndicatorSelectedIndexProperty =
  89. DependencyProperty.Register("IndicatorSelectedIndex", typeof(int), typeof(NavigationPanel), new PropertyMetadata(0, IndicatorSelectedIndexCallback));
  90. private static void IndicatorSelectedIndexCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
  91. {
  92. NavigationPanel navigationPanel = d as NavigationPanel;
  93. int index = (int)e.NewValue;
  94. if (navigationPanel != null && navigationPanel.mHeaderList != null && index < navigationPanel.mHeaderList.Count)
  95. {
  96. object item = navigationPanel.mHeaderList[index];
  97. navigationPanel.ScrollToSelection(item);
  98. }
  99. }
  100. #endregion
  101. #endregion
  102. #region Constructors
  103. static NavigationPanel()
  104. {
  105. DefaultStyleKeyProperty.OverrideMetadata(typeof(NavigationPanel), new FrameworkPropertyMetadata(typeof(NavigationPanel)));
  106. }
  107. #endregion
  108. #region Override
  109. public override void OnApplyTemplate()
  110. {
  111. base.OnApplyTemplate();
  112. this.Loaded += NavigationPanel_Loaded;
  113. this.PART_Indicator = this.GetTemplateChild("PART_Indicator") as SegmentControl;
  114. this.PART_ContentPresenter = this.GetTemplateChild("PART_ContentPresenter") as ContentPresenter;
  115. if (this.PART_Indicator != null)
  116. {
  117. this.PART_Indicator.ItemClick += PART_Indicator_ItemClick;
  118. }
  119. }
  120. #endregion
  121. #region private function
  122. /// <summary>
  123. /// 滚动至指定Item
  124. /// </summary>
  125. /// <param name="selection"></param>
  126. private void ScrollToSelection(object selection)
  127. {
  128. if (this.mScrollViewer == null)
  129. {
  130. return;
  131. }
  132. for (int i = 0; i < this.mHeaderList.Count; i++)
  133. {
  134. if (this.mHeaderList[i] == selection)
  135. {
  136. //获取子项相对于控件的位置
  137. GeneralTransform generalTransform1 = this.mHeaderList[i].TransformToAncestor(this.PART_ContentPresenter);
  138. Point currentPoint = generalTransform1.Transform(new Point(0, 0));
  139. double offsetY = this.mScrollViewer.VerticalOffset + currentPoint.Y;
  140. this.mScrollViewer.ScrollToVerticalOffset(offsetY);
  141. //DoubleAnimation doubleAnimation = new DoubleAnimation(this.oldOffsetY, offsetY, new Duration(TimeSpan.FromMilliseconds(500)));
  142. //this.mScrollViewer.BeginAnimation(ZScrollViewer.VerticalOffsetExProperty, doubleAnimation);
  143. //this.oldOffsetY = offsetY;
  144. //this.IndicatorSelectedIndex = i;
  145. break;
  146. }
  147. }
  148. }
  149. #endregion
  150. #region Event Implement Function
  151. private void NavigationPanel_Loaded(object sender, RoutedEventArgs e)
  152. {
  153. mHeaderList = Utils.VisualHelper.FindVisualChildrenEx<ZGroupBox>(this.PART_ContentPresenter);
  154. if (mHeaderList != null)
  155. {
  156. List<object> list = new List<object>();
  157. mHeaderList.ForEach(p => list.Add(p));
  158. this.ItemsSource = list;
  159. }
  160. this.mScrollViewer = Utils.VisualHelper.FindVisualChild<ScrollViewer>(this.PART_ContentPresenter);
  161. if (this.mScrollViewer != null)
  162. {
  163. this.mScrollViewer.ScrollChanged += MScrollViewer_ScrollChanged;
  164. }
  165. object item = this.mHeaderList[this.IndicatorSelectedIndex];
  166. this.ScrollToSelection(item);
  167. }
  168. /// <summary>
  169. /// 点击指示器,滚动至指定位置
  170. /// </summary>
  171. /// <param name="sender"></param>
  172. /// <param name="e"></param>
  173. private void PART_Indicator_ItemClick(object sender, RoutedPropertyChangedEventArgs<object> e)
  174. {
  175. var item = this.PART_Indicator.SelectedItem;
  176. this.ScrollToSelection(item);
  177. }
  178. /// <summary>
  179. /// 当滚动条位置发生改变时,选中指示器
  180. /// </summary>
  181. /// <param name="sender"></param>
  182. /// <param name="e"></param>
  183. private void MScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
  184. {
  185. var verticalOffset = this.mScrollViewer.VerticalOffset;
  186. if (verticalOffset > 0)
  187. {
  188. double scrollOffset = 0.0;
  189. for (int i = 0; i < this.mHeaderList.Count; i++)
  190. {
  191. var child = this.mHeaderList[i];
  192. if (child is FrameworkElement)
  193. {
  194. FrameworkElement element = child as FrameworkElement;
  195. if (element == null) return;
  196. scrollOffset += element.ActualHeight;
  197. if (scrollOffset > verticalOffset && i < this.mHeaderList.Count)
  198. {
  199. //this.IndicatorSelectedIndex = i;
  200. this.PART_Indicator.SelectedItem = this.mHeaderList[i];
  201. break;
  202. }
  203. }
  204. }
  205. }
  206. }
  207. #endregion
  208. }
  209. }