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 }
但是需要注意的是,這樣寫思路倒是簡單,就是數據量大的清空可能會影響效率,慎用!