windows phone开发学习--LoopingSelector

其实在上一篇自定义datetimepicker中已经提到了LoopingSelector,这是一个带有滚动效果的控件,要比list那种控件美观的多,用户体验也要好不少。微软自带的控件中是没有这个控件的,在silverlight中才有,下载最新的toolkit,然后引用

	xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls.Primitives;assembly=Microsoft.Phone.Controls.Toolkit"

就可以在xaml中添加loopingselector了

	<toolkit:LoopingSelector Grid.Column="0" x:Name="selectorDouble" ItemMargin="2,3,3,2" ItemSize="100,100" FontSize="33"/>
			


不过很多时候,我发现loopingselector显示的是简单的整型数字,日期控件中就是如此,显然这是远远不够的,我们应该能让他显示浮点型,字符串类型,甚至还包括图片,效果就像下面一样

windows phone开发学习--LoopingSelector_第1张图片


这些资料其实网上都有说,WP7 LoopingSelector in depth给出了详细的实现过程,具体看这里:http://windowsphonegeek.com/articles/WP7-LoopingSelector-in-depth--Part3-Advanced-data-binding


针对我目前所做的项目,我只需要显示农历中的月份和天数即可,参考了一下作者的源码,发现实现很简单,甚至不需要像之前自定义datetimepicker控件那样弄出两个单独的类,这些类本可以放在一起,甚至可以针对任意类型,所以实现浮点型还是字符串,图片等等不在话下。

最关键的是下面两个函数,其他一切都好办

// abstract the reusable code in a base class
		// this will allow us to concentrate on the specifics when implementing deriving looping data source classes
		public abstract class LoopingDataSourceBase : ILoopingSelectorDataSource
		{
			private object selectedItem;

			#region ILoopingSelectorDataSource Members

			public abstract object GetNext(object relativeTo);

			public abstract object GetPrevious(object relativeTo);

			public object SelectedItem
			{
				get
				{
					return this.selectedItem;
				}
				set
				{
					// this will use the Equals method if it is overridden for the data source item class
					if (!object.Equals(this.selectedItem, value))
					{
						// save the previously selected item so that we can use it 
						// to construct the event arguments for the SelectionChanged event
						object previousSelectedItem = this.selectedItem;
						this.selectedItem = value;
						// fire the SelectionChanged event
						this.OnSelectionChanged(previousSelectedItem, this.selectedItem);
					}
				}
			}

			public event EventHandler<SelectionChangedEventArgs> SelectionChanged;

			protected virtual void OnSelectionChanged(object oldSelectedItem, object newSelectedItem)
			{
				EventHandler<SelectionChangedEventArgs> handler = this.SelectionChanged;
				if (handler != null)
				{
					handler(this, new SelectionChangedEventArgs(new object[] { oldSelectedItem }, new object[] { newSelectedItem }));
				}
			}

			#endregion
		}

		public class ListLoopingDataSource<T> : LoopingDataSourceBase
		{
			private LinkedList<T> linkedList;
			private List<LinkedListNode<T>> sortedList;
			private IComparer<T> comparer;
			private NodeComparer nodeComparer;

			public ListLoopingDataSource()
			{
			}

			public IEnumerable<T> Items
			{
				get
				{
					return this.linkedList;
				}
				set
				{
					this.SetItemCollection(value);
				}
			}

			private void SetItemCollection(IEnumerable<T> collection)
			{
				this.linkedList = new LinkedList<T>(collection);

				this.sortedList = new List<LinkedListNode<T>>(this.linkedList.Count);
				// initialize the linked list with items from the collections
				LinkedListNode<T> currentNode = this.linkedList.First;
				while (currentNode != null)
				{
					this.sortedList.Add(currentNode);
					currentNode = currentNode.Next;
				}

				IComparer<T> comparer = this.comparer;
				if (comparer == null)
				{
					// if no comparer is set use the default one if available
					if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
					{
						comparer = Comparer<T>.Default;
					}
					else
					{
						throw new InvalidOperationException("There is no default comparer for this type of item. You must set one.");
					}
				}

				this.nodeComparer = new NodeComparer(comparer);
				this.sortedList.Sort(this.nodeComparer);
			}

			public IComparer<T> Comparer
			{
				get
				{
					return this.comparer;
				}
				set
				{
					this.comparer = value;
				}
			}

			public override object GetNext(object relativeTo)
			{
				// find the index of the node using binary search in the sorted list
				int index = this.sortedList.BinarySearch(new LinkedListNode<T>((T)relativeTo), this.nodeComparer);
				if (index < 0)
				{
					return default(T);
				}

				// get the actual node from the linked list using the index
				LinkedListNode<T> node = this.sortedList[index].Next;
				if (node == null)
				{
					// if there is no next node get the first one
					node = this.linkedList.First;
				}
				return node.Value;
			}

			public override object GetPrevious(object relativeTo)
			{
				int index = this.sortedList.BinarySearch(new LinkedListNode<T>((T)relativeTo), this.nodeComparer);
				if (index < 0)
				{
					return default(T);
				}
				LinkedListNode<T> node = this.sortedList[index].Previous;
				if (node == null)
				{
					// if there is no previous node get the last one
					node = this.linkedList.Last;
				}
				return node.Value;
			}

			private class NodeComparer : IComparer<LinkedListNode<T>>
			{
				private IComparer<T> comparer;

				public NodeComparer(IComparer<T> comparer)
				{
					this.comparer = comparer;
				}

				#region IComparer<LinkedListNode<T>> Members

				public int Compare(LinkedListNode<T> x, LinkedListNode<T> y)
				{
					return this.comparer.Compare(x.Value, y.Value);
				}

				#endregion
			}

然后我们就可以在页面初始化的时候给loopingselector设定数据源,然后绑定一下就OK,在作者的例子中给出了一次全部定义和每次添加一个的方法

	public MainPage()
		{
			InitializeComponent();
			string[] cityNames = new string[] { "London", "New York", "Barcelona", "Madrid", "Berlin", "Bonn", "Munich", "Las Vegas" };
			this.selectorString.DataSource = new ListLoopingDataSource<string>() { Items = cityNames, SelectedItem = "Madrid" };

			List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
			this.selectorInt.DataSource = new ListLoopingDataSource<int>() { Items = numbers, SelectedItem = 5 };

			List<DateTime> dates = new List<DateTime>();
			DateTime selectedDate = DateTime.Now;
			dates.Add(selectedDate);
			dates.Add(DateTime.Now.AddMonths(1));
			dates.Add(DateTime.Now.AddMonths(2));
			dates.Add(DateTime.Now.AddMonths(3));
			dates.Add(DateTime.Now.AddMonths(4));
			dates.Add(DateTime.Now.AddMonths(5));
			dates.Add(DateTime.Now.AddMonths(6));
			this.selectorDateTime.DataSource = new ListLoopingDataSource<DateTime>() { Items = dates, SelectedItem = selectedDate };

			List<double> doubleNumbers = new List<double> { 1.1, 2.15, 3.66, 4.457, 5.036, 6.7, 7.4, 8.54, 9.11 };
			this.selectorDouble.DataSource = new ListLoopingDataSource<double>() { Items = doubleNumbers, SelectedItem = 6.7 };
		}


最终实现的效果如下

windows phone开发学习--LoopingSelector_第2张图片


其实我觉得不需要做成用户控件,干脆做成页面比较方便,toolkit中自带的datetimepicker其实都是一个页面,与其做个控件,然后再做个页面上面放这个控件,真不如一步到位实现。

你可能感兴趣的:(windows,object,null,Class,silverlight,phone,Numbers)