WPF ListView 選中問題
摘自:http://www.cnblogs.com/BBHor/archive/2013/04/28/VisualTreeHelper-PreviewMouseDown.html
在項目中遇到了這樣的問題,ListView通過數據綁定,有模板的情況下ListViewItem 里面的子控件點擊之后默認是子控件獲得焦點而不是Item獲的焦點。
往往需要獲取一個ListViewItem 而不是他的子控件,這時候應該怎么辦呢?
先看前台XAML:
1 <ListView x:Name="lv_VMlist"
2 PreviewMouseDown="lv_VMlist_PreviewMouseDown"
3 SelectionChanged="lv_VMlist_SelectionChanged">
4 <ListView.View>
5 <GridView>
6 <GridView.Columns>
7 <GridViewColumn Width="100"
8 DisplayMemberBinding="{Binding CallerID}"
9 Header="主叫方號碼" />
10 <GridViewColumn Width="110"
11 DisplayMemberBinding="{Binding Duration}"
12 Header="語音郵件長度" />
13 <GridViewColumn Width="70"
14 DisplayMemberBinding="{Binding External}"
15 Header="是否是外線" />
16 <GridViewColumn Width="80"
17 DisplayMemberBinding="{Binding Type,
18 Converter={StaticResource etsc}}"
19 Header="類型" />
20 <GridViewColumn Width="70"
21 DisplayMemberBinding="{Binding AttachCount}"
22 Header="附件個數" />
23 <GridViewColumn Width="120"
24 DisplayMemberBinding="{Binding Time}"
25 Header="時間" />
26 <GridViewColumn Width="180" Header="操作">
27 <GridViewColumn.CellTemplate>
28 <HierarchicalDataTemplate>
29 <StackPanel Name="stackPanel" Orientation="Horizontal">
30 <Button Name="btnPlay"
31 Margin="0,0,5,0"
32 Command="{Binding RelativeSource={RelativeSource FindAncestor,
33 AncestorLevel=1,
34 AncestorType={x:Type ListView}},
35 Path=DataContext.OnPlay}"
36 Content="播放"
37 Focusable="False" />
38 <Button Name="btnStop"
39 Margin="0,0,5,0"
40 Command="{Binding RelativeSource={RelativeSource FindAncestor,
41 AncestorLevel=1,
42 AncestorType={x:Type ListView}},
43 Path=DataContext.OnStop}"
44 Content="停止" />
45 <Button Name="btnSaveAs"
46 Margin="0,0,5,0"
47 Click="btnSaveClick"
48 Content="另存為"
49 ToolTip="將語音郵件保存到本地" />
50 <Button Name="btnDel"
51 Margin="0,0,5,0"
52 Command="{Binding RelativeSource={RelativeSource FindAncestor,
53 AncestorLevel=1,
54 AncestorType={x:Type ListView}},
55 Path=DataContext.OnDelete}"
56 Content="刪除"
57 ToolTip="刪除本條語音郵件" />
58 <Button Name="btnSendTo"
59 Margin="0,0,5,0"
60 Content="轉發"
61 ToolTip="將本條語音郵件轉發給他人" />
62 </StackPanel>
63 </HierarchicalDataTemplate>
64 </GridViewColumn.CellTemplate>
65 </GridViewColumn>
66 </GridView.Columns>
67 </GridView>
68 </ListView.View>
69 </ListView>
要下手去尋找這時候得借助WPF里面的一個神奇的類:VisualTreeHelper 有了這個類幾乎能得到界面的任何東西。當然了,先行條件是在子控件的事件觸發之前就要出發一個事件去獲取ListViewItem,此時我們想到一個事件就是PreviewMouseDown,因為他是鼠標事件,所以優先級比較高,當他觸發了之后才會觸發子控件的一些Click事件等
1 private void lv_VMlist_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
2 {
3 int index = -1;
4 DependencyObject depObj = e.OriginalSource as DependencyObject;
5
6 if (depObj == null) return;
7
8 do
9 {
10 depObj = VisualTreeHelper.GetParent(depObj);
11
12 //有可能是點擊到listviewitem之外的東西,例如滾動條,這時候會為null
13 if (depObj == null) break;
14
15 //得到listviewitem
16 if (depObj.GetType() == typeof(ListViewItem))
17 {
18 //再去獲取父級,用來得到索引
19 DependencyObject parent = VisualTreeHelper.GetParent(depObj);
20
21 for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
22 {
23 if (depObj == VisualTreeHelper.GetChild(parent, i))
24 {
25 //得到索引后馬上跳出
26 index = i;
27 break;
28 }
29 }
30 break;
31 }
32 }
33 while (depObj != null);
34
35 //證明已經找到
36 if (index > -1)
37 {
38 lv_VMlist.SelectedIndex = index;
39 }
40 }
但是需要注意的是,這樣寫思路倒是簡單,就是數據量大的清空可能會影響效率,慎用!

