最近开始接触WP7的开发,遇到一个需求,简要的概述如下:
有两个画面,第一个画面中有一个用于输入的TextBox;第二个画面是一个 LongListSelector控件。当第一个画面输入内容后,跳转到第二个画面,如果第二个画面中LongListSelector的数据中有和TextBox输入内容相同的条目,那么选中这个条目,并且使得条目处于屏幕的中间。
对于LongListSelector和ListBox来说,其视图结构中都包含一个ScrollViewer,区别只在于ScrollViewer所处于的层次会有所不同。对于LongListSelector来说,它内在的第一层是一个TemplatedListBox,第二层才是ScrollViewer,而对于ListBox第一层就是ScrollViewer。我解决这个问题的关键就在于找到控件中的ScrollViewer,并使用它的ScrollToVerticalOffset方法。怎么找这个控件呢,办法是调用 VisualTreeHelper.GetChild(DependencyObject reference, int childIndex)方法。可以使用递归来完成这个步骤:
2 {
3 int childCount = VisualTreeHelper.GetChildrenCount(parent);
4 UIElement returnElement = null;
5 if (childCount > 0)
6 {
7 for (int i = 0; i < childCount; i++)
8 {
9 Object element = VisualTreeHelper.GetChild(parent, i);
10 if (element.GetType() == targetType)
11 {
12 return element as UIElement;
13 }
14 else
15 {
16 returnElement = FindElementRecursive(VisualTreeHelper.GetChild(parent, i) as FrameworkElement, targetType);
17 }
18 }
19 }
20 return returnElement;
21
其中参数第一个是你放入的控件,本文中就是LongListSelector或者ListBox,第二个参数是你希望找到的控件,本文中就是ScrollViewer。
2 bool find = false;
3
4 foreach (CountryCodeInGroup countryCodeInGroup in LongListSelectorSource)
5 {
6 if (find == true) break;
7 if (countryCodeInGroup.Key == inputCountryCode.ID.Substring(0,1).ToLower())
8 {
9 foreach (CountryCode countryCode in countryCodeInGroup)
10 {
11 if (countryCode.ID == inputCountryCode.ID)
12 {
13 find = true;
14 break;
15 }
16 else
17 {
18 offset += 1;
19 }
20 }
21 }
22 else
23 {
24 if (countryCodeInGroup.Count != 0)
25 {
26 offset += countryCodeInGroup.Count + 1;
27 }
28 }
29
最后一步:ScrollViewer.ScrollToVerticalOffset(offset);
这个时候可能会考虑一个问题,就是我们在工作日很多时候是在DataTemplate中做些文章,如果我的DataTemplate做的很复杂会影响这个偏移量嘛?答案是不会的,不论是ListBox还是LongListSelector,我们计算的offset实际上都是一个Item的index。
最后说明几点:
1、发现2.5这个修正值似乎在ListBox和LongListSelector都通用,这个值是我肉眼修正的。
3、吐槽一下LongListSelector.GetItemsWithContainers方法。