看见有人在微薄上讨论图片滚动的实现
水平有限搞不定,突然想起来SL ToolKits有个仿wp上日期、时间滚动的控件
定制下模版就比较形似图片滚动了
动手试试效果
首先找了120张WP壁纸,不过文件都比较小
然后新建工程,添加引用Microsoft.Phone.Controls.Toolkit.dll,添加图片,生成方式设为内容
参考Windows Phone Toolkit In Depth,使用LoopingSelector
首先创建类ListLoopingDataSource.cs
1 using System;
2 using System.Windows.Controls;
3 using Microsoft.Phone.Controls.Primitives;
4 namespace LoopingSelectorpic
5 {
6 public abstract class LoopingDataSourceBase : ILoopingSelectorDataSource
7 {
8 private object selectedItem;
9
10 #region ILoopingSelectorDataSource Members
11
12 public abstract object GetNext(object relativeTo);
13
14 public abstract object GetPrevious(object relativeTo);
15
16 public object SelectedItem
17 {
18 get
19 {
20 return this.selectedItem;
21 }
22 set
23 {
24 // this will use the Equals method if it is overridden for the data source item class
25 if (!object.Equals(this.selectedItem, value))
26 {
27 // save the previously selected item so that we can use it
28 // to construct the event arguments for the SelectionChanged event
29 object previousSelectedItem = this.selectedItem;
30 this.selectedItem = value;
31 // fire the SelectionChanged event
32 this.OnSelectionChanged(previousSelectedItem, this.selectedItem);
33 }
34 }
35 }
36 public event EventHandler<SelectionChangedEventArgs> SelectionChanged;
37
38 protected virtual void OnSelectionChanged(object oldSelectedItem, object newSelectedItem)
39 {
40 EventHandler<SelectionChangedEventArgs> handler =
41 this.SelectionChanged;
42 if (handler != null)
43 {
44 handler(this, new SelectionChangedEventArgs(new object[] { oldSelectedItem }, new object[] { newSelectedItem }));
45 }
46 }
47
48 #endregion
49 }
50 }
2 using System.Windows.Controls;
3 using Microsoft.Phone.Controls.Primitives;
4 namespace LoopingSelectorpic
5 {
6 public abstract class LoopingDataSourceBase : ILoopingSelectorDataSource
7 {
8 private object selectedItem;
9
10 #region ILoopingSelectorDataSource Members
11
12 public abstract object GetNext(object relativeTo);
13
14 public abstract object GetPrevious(object relativeTo);
15
16 public object SelectedItem
17 {
18 get
19 {
20 return this.selectedItem;
21 }
22 set
23 {
24 // this will use the Equals method if it is overridden for the data source item class
25 if (!object.Equals(this.selectedItem, value))
26 {
27 // save the previously selected item so that we can use it
28 // to construct the event arguments for the SelectionChanged event
29 object previousSelectedItem = this.selectedItem;
30 this.selectedItem = value;
31 // fire the SelectionChanged event
32 this.OnSelectionChanged(previousSelectedItem, this.selectedItem);
33 }
34 }
35 }
36 public event EventHandler<SelectionChangedEventArgs> SelectionChanged;
37
38 protected virtual void OnSelectionChanged(object oldSelectedItem, object newSelectedItem)
39 {
40 EventHandler<SelectionChangedEventArgs> handler =
41 this.SelectionChanged;
42 if (handler != null)
43 {
44 handler(this, new SelectionChangedEventArgs(new object[] { oldSelectedItem }, new object[] { newSelectedItem }));
45 }
46 }
47
48 #endregion
49 }
50 }
然后创建类LoopingDataSourceBase.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Collections;
4 namespace LoopingSelectorpic
5 {
6 public class ListLoopingDataSource<T> : LoopingDataSourceBase
7 {
8 private LinkedList<T> linkedList;
9 private List<LinkedListNode<T>> sortedList;
10 private IComparer<T> comparer;
11 private NodeComparer nodeComparer;
12
13 public ListLoopingDataSource()
14 {
15 }
16
17 public IEnumerable<T> Items
18 {
19 get
20 {
21 return this.linkedList;
22 }
23 set
24 {
25 this.SetItemCollection(value);
26 }
27 }
28
29 private void SetItemCollection(IEnumerable<T> collection)
30 {
31 this.linkedList = new LinkedList<T>(collection);
32
33 this.sortedList = new
34 List<LinkedListNode<T>>(this.linkedList.Count);
35 // initialize the linked list with items from the collections
36 LinkedListNode<T> currentNode = this.linkedList.First;
37 while (currentNode != null)
38 {
39 this.sortedList.Add(currentNode);
40 currentNode = currentNode.Next;
41 }
42
43 IComparer<T> comparer = this.comparer;
44 if (comparer == null)
45 {
46 // if no comparer is set use the default one if available
47 if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
48 {
49 comparer = Comparer<T>.Default;
50 }
51 else
52 {
53 throw new InvalidOperationException("There is no default comparer for this type of item. You must set one.");
54 }
55 }
56
57 this.nodeComparer = new NodeComparer(comparer);
58 this.sortedList.Sort(this.nodeComparer);
59 }
60
61 public IComparer<T> Comparer
62 {
63 get
64 {
65 return this.comparer;
66 }
67 set
68 {
69 this.comparer = value;
70 }
71 }
72
73 public override object GetNext(object relativeTo)
74 {
75 // find the index of the node using binary search in the sorted list
76 int index = this.sortedList.BinarySearch(new
77 LinkedListNode<T>((T)relativeTo), this.nodeComparer);
78 if (index < 0)
79 {
80 return default(T);
81 }
82
83 // get the actual node from the linked list using the index
84 LinkedListNode<T> node = this.sortedList[index].Next;
85 if (node == null)
86 {
87 // if there is no next node get the first one
88 node = this.linkedList.First;
89 }
90 return node.Value;
91 }
92
93 public override object GetPrevious(object relativeTo)
94 {
95 int index = this.sortedList.BinarySearch(new
96 LinkedListNode<T>((T)relativeTo), this.nodeComparer);
97 if (index < 0)
98 {
99 return default(T);
100 }
101 LinkedListNode<T> node = this.sortedList[index].Previous;
102 if (node == null)
103 {
104 // if there is no previous node get the last one
105 node = this.linkedList.Last;
106 }
107 return node.Value;
108 }
109
110 private class NodeComparer : IComparer<LinkedListNode<T>>
111 {
112 private IComparer<T> comparer;
113
114 public NodeComparer(IComparer<T> comparer)
115 {
116 this.comparer = comparer;
117 }
118
119 #region IComparer<LinkedListNode<T>> Members
120
121 public int Compare(LinkedListNode<T> x, LinkedListNode<T> y)
122 {
123 return this.comparer.Compare(x.Value, y.Value);
124 }
125
126 #endregion
127 }
128
129 }
130 }
2 using System.Collections.Generic;
3 using System.Collections;
4 namespace LoopingSelectorpic
5 {
6 public class ListLoopingDataSource<T> : LoopingDataSourceBase
7 {
8 private LinkedList<T> linkedList;
9 private List<LinkedListNode<T>> sortedList;
10 private IComparer<T> comparer;
11 private NodeComparer nodeComparer;
12
13 public ListLoopingDataSource()
14 {
15 }
16
17 public IEnumerable<T> Items
18 {
19 get
20 {
21 return this.linkedList;
22 }
23 set
24 {
25 this.SetItemCollection(value);
26 }
27 }
28
29 private void SetItemCollection(IEnumerable<T> collection)
30 {
31 this.linkedList = new LinkedList<T>(collection);
32
33 this.sortedList = new
34 List<LinkedListNode<T>>(this.linkedList.Count);
35 // initialize the linked list with items from the collections
36 LinkedListNode<T> currentNode = this.linkedList.First;
37 while (currentNode != null)
38 {
39 this.sortedList.Add(currentNode);
40 currentNode = currentNode.Next;
41 }
42
43 IComparer<T> comparer = this.comparer;
44 if (comparer == null)
45 {
46 // if no comparer is set use the default one if available
47 if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
48 {
49 comparer = Comparer<T>.Default;
50 }
51 else
52 {
53 throw new InvalidOperationException("There is no default comparer for this type of item. You must set one.");
54 }
55 }
56
57 this.nodeComparer = new NodeComparer(comparer);
58 this.sortedList.Sort(this.nodeComparer);
59 }
60
61 public IComparer<T> Comparer
62 {
63 get
64 {
65 return this.comparer;
66 }
67 set
68 {
69 this.comparer = value;
70 }
71 }
72
73 public override object GetNext(object relativeTo)
74 {
75 // find the index of the node using binary search in the sorted list
76 int index = this.sortedList.BinarySearch(new
77 LinkedListNode<T>((T)relativeTo), this.nodeComparer);
78 if (index < 0)
79 {
80 return default(T);
81 }
82
83 // get the actual node from the linked list using the index
84 LinkedListNode<T> node = this.sortedList[index].Next;
85 if (node == null)
86 {
87 // if there is no next node get the first one
88 node = this.linkedList.First;
89 }
90 return node.Value;
91 }
92
93 public override object GetPrevious(object relativeTo)
94 {
95 int index = this.sortedList.BinarySearch(new
96 LinkedListNode<T>((T)relativeTo), this.nodeComparer);
97 if (index < 0)
98 {
99 return default(T);
100 }
101 LinkedListNode<T> node = this.sortedList[index].Previous;
102 if (node == null)
103 {
104 // if there is no previous node get the last one
105 node = this.linkedList.Last;
106 }
107 return node.Value;
108 }
109
110 private class NodeComparer : IComparer<LinkedListNode<T>>
111 {
112 private IComparer<T> comparer;
113
114 public NodeComparer(IComparer<T> comparer)
115 {
116 this.comparer = comparer;
117 }
118
119 #region IComparer<LinkedListNode<T>> Members
120
121 public int Compare(LinkedListNode<T> x, LinkedListNode<T> y)
122 {
123 return this.comparer.Compare(x.Value, y.Value);
124 }
125
126 #endregion
127 }
128
129 }
130 }
然后定义我们的数据类Picdata.cs
1 using System;
2 using System.Net;
3 using System.Windows;
4 using System.Windows.Controls;
5 using System.Windows.Documents;
6 using System.Windows.Ink;
7 using System.Windows.Input;
8 using System.Windows.Media;
9 using System.Windows.Media.Animation;
10 using System.Windows.Shapes;
11
12 namespace LoopingSelectorpic
13 {
14 public class Picdata : IComparable<Picdata>
15 {
16 public string Name
17 {
18 get;
19 set;
20 }
21
22 public string Url
23 {
24 get;
25 set;
26 }
27 public int ID
28 {
29 get;
30 set;
31 }
32
33 #region IComparable<Picdata> Members
34
35 public int CompareTo(Picdata other)
36 {
37 return this.ID.CompareTo(other.ID);
38 }
39
40 #endregion
41 }
42 }
2 using System.Net;
3 using System.Windows;
4 using System.Windows.Controls;
5 using System.Windows.Documents;
6 using System.Windows.Ink;
7 using System.Windows.Input;
8 using System.Windows.Media;
9 using System.Windows.Media.Animation;
10 using System.Windows.Shapes;
11
12 namespace LoopingSelectorpic
13 {
14 public class Picdata : IComparable<Picdata>
15 {
16 public string Name
17 {
18 get;
19 set;
20 }
21
22 public string Url
23 {
24 get;
25 set;
26 }
27 public int ID
28 {
29 get;
30 set;
31 }
32
33 #region IComparable<Picdata> Members
34
35 public int CompareTo(Picdata other)
36 {
37 return this.ID.CompareTo(other.ID);
38 }
39
40 #endregion
41 }
42 }
然后在页面里添加LoopingSelector并定义模版(貌似工具箱里找不到,自己手打吧)
<toolkit:LoopingSelector x:Name="LoopingSelector1" ItemMargin="5" ItemSize="400,530" HorizontalAlignment="Center" VerticalAlignment="Center" Width="400" Height="696" >
<toolkit:LoopingSelector.ItemTemplate>
<DataTemplate>
<StackPanel>
<StackPanel Width="400" Height="30">
<TextBlock Text="{Binding Name}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
<Image Source="{Binding Url}" Stretch="Fill" Width="400" Height="500"/>
<TextBlock Text="{Binding ID}"/>
</StackPanel>
</DataTemplate>
</toolkit:LoopingSelector.ItemTemplate>
</toolkit:LoopingSelector>
<toolkit:LoopingSelector.ItemTemplate>
<DataTemplate>
<StackPanel>
<StackPanel Width="400" Height="30">
<TextBlock Text="{Binding Name}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
<Image Source="{Binding Url}" Stretch="Fill" Width="400" Height="500"/>
<TextBlock Text="{Binding ID}"/>
</StackPanel>
</DataTemplate>
</toolkit:LoopingSelector.ItemTemplate>
</toolkit:LoopingSelector>
最后在page_load里填充数据并绑定
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
List<Picdata> data = new List<Picdata>();
for (int i = 1; i <= 120; i++)
{
data.Add(new Picdata()
{
Name = i.ToString() + ".jpg",
Url = new Uri("/pic/"+ i.ToString() +".jpg",UriKind.Relative).ToString(),
ID = i
});
}
this.LoopingSelector1.DataSource = new ListLoopingDataSource<Picdata>()
{
Items = data,
SelectedItem = data[2]
};
}
{
List<Picdata> data = new List<Picdata>();
for (int i = 1; i <= 120; i++)
{
data.Add(new Picdata()
{
Name = i.ToString() + ".jpg",
Url = new Uri("/pic/"+ i.ToString() +".jpg",UriKind.Relative).ToString(),
ID = i
});
}
this.LoopingSelector1.DataSource = new ListLoopingDataSource<Picdata>()
{
Items = data,
SelectedItem = data[2]
};
}
看下效果:
后记:加载120张图片,模拟器还算流畅,不过真机滚动起来还是有明显的卡顿
估计图片少点的时候凑合能用吧,另外理论上旋转下可以横向滚动的,不过我旋转的貌似有点问题,总是位置不大合适,而且只有点击图片边缘部分才能滚动,望高手能指导下
源码: