WP8: 一个在ListBox 中ItemTemplate中放入ScrollViewer导致SelectedChangd不能触发的状况,及其解决办法
在做Windows Phone App开发中,有一项内容是使用ListBox并且将TextBlock放到ItemTemplate中,参考以下代码:
1: <ListBox x:Name="MyListBox" HorizontalAlignment="Left" SelectionChanged="MyListBox_SelectionChanged" >
2: <ListBox.ItemTemplate>
3: <DataTemplate>
4: <StackPanel Orientation="Horizontal" Background="Blue" Height="80" Margin="15,0,0,7">
5: <TextBlock Text="{Binding SomeContent}" FontSize="25"/>
6: </StackPanel>
7: </DataTemplate>
8: </ListBox.ItemTemplate>
9: </ListBox>
在这个示例中,我创建了一个ListBox,并且把TextBlock放到了ItemTemplate中。在把TextBlock填充完之前,都是好的。
当我把StackPanel固定高度后,TextBlock不能显示全部内容。不过如果不这样,这个列表里面的内容就会显示很乱。所以,我决定在TextBlock旁边加一个ScrollViewer,这样用户就可以上下滑动显示内容。
1: <ListBox x:Name="MyListBox" HorizontalAlignment="Left" SelectionChanged="MyListBox_SelectionChanged" >
2: <ListBox.ItemTemplate>
3: <DataTemplate>
4: <StackPanel Orientation="Horizontal" Background="Blue" Height="80">
5: <ScrollViewer HorizontalScrollBarVisibility="Hidden">
6: <TextBlock Text="{Binding SomeContent}" FontSize="25"/>
7: </ScrollViewer>
8: </StackPanel>
9: </DataTemplate>
10: </ListBox.ItemTemplate>
11: </ListBox>
不过,这样做过之后,问题就会出现了!SelectionChanged事件没有办法探测到事件改编,虽然TextBlock中的文字可以滑动。这样会导致一个后果,就是我们没有办法与之交互,例如没有办法通过点击跳转到另外页面。
为了追根究底发生了什么,我放了一个Tap事件到StackPanel里面,这里面含有一个ScrollViewer。调试的结果如下,无论哪一个ListItem被点击了,ListBox中SelectedIndex一直被标为-1. 这样导致的后果就是,ScrollViewer探知哪一个ListBox被选中的方法被禁止了。像是Windows Store App开发中的 Gestures, manipulations, and interactions,Windows Phone对ScrollViewer的交互做了定义,这有时候会让开发人员感到困惑,因为它不能给我们一个正确的反馈。
不过,这里有一个短小的代码片段可以解决这个问题,
1: <ListBox x:Name="MyListBox" HorizontalAlignment="Left" SelectionChanged="MyListBox_SelectionChanged" >
2: <ListBox.ItemTemplate>
3: <DataTemplate>
4: <StackPanel Orientation="Horizontal" Background="Blue" Height="80" Tap="StackPanel_Tap">
5: <ScrollViewer HorizontalScrollBarVisibility="Hidden">
6: <TextBlock Text="{Binding Name}" FontSize="25"/>
7: </ScrollViewer>
8: </StackPanel>
9: </DataTemplate>
10: </ListBox.ItemTemplate>
11: </ListBox>
在这个XAML代码后面,我定义了一个FindParent方法去得到某一特定类型的第一个父类。虽然很简单,但是很有效:
1: private void StackPanel_Tap(object sender, GestureEventArgs e)
2: {
3: var listitem = FindParent(sender as StackPanel, typeof(ListBoxItem)) as ListBoxItem;
4: listitem.IsSelected = true;
5: }
6:
7: private DependencyObject FindParent(DependencyObject child, Type type)
8: {
9: var parent = VisualTreeHelper.GetParent(child);
10:
11: if (parent != null && !type.IsInstanceOfType(parent))
12: return FindParent(parent, type);
13: else
14: return parent;
15: }
最终,ListBox和ScrollViewer中的SelectionChanged工作正常了!
English Version: https://blogs.msdn.com/b/lighthouse/archive/2013/10/21/windows-phone-8-app-scrollviewer-issue-inside-item-template-with-selectedchanged-in-listbox.aspx
Comments
- Anonymous
March 20, 2014
The comment has been removed - Anonymous
March 22, 2014
The comment has been removed