Em WPF, como faço para selecionar o item de treeview sob o meu cursor no botão direito do mouse?
-
18-09-2019 - |
Pergunta
Em WPF, quando eu clique com o botão direito em um item de treeview Eu gostaria que ele seja selecionado / ativado antes de mostrar o menu de contexto.
Este sons muito simples, mas a inclusão de um hierachicalDataTemplate complica as coisas um pouco.
Eu tenho o seguinte treeview:
<TreeView
x:Name="trv"
ContextMenu="{StaticResource contextMenu}"
ItemTemplate="{StaticResource treeHierarchicalDataTemplate}"
ItemsSource="{Binding Source={StaticResource meetingItems}}" >
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<EventSetter Event="TreeViewItem.PreviewMouseRightButtonDown" Handler="trv_PreviewMouseRightButtonDown"/>
<Setter Property="IsExpanded" Value="True"></Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
E aqui está o meu evento manipulador ...
private void trv_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem item = sender as TreeViewItem;
if (item != null)
{
item.Focus();
e.Handled = true;
}
}
Note como eu adicionar um EventSetter acima. Esta quase funciona. Mas só seleciona o nó treeview de nível raiz (ou seja, o pai raiz do nó em que eu botão direito). Isso pode ser por causa do meu modelo de dados hierárquico? Este modelo pode conter filhos do mesmo tipo.
Aqui está o meu dados hierárquicos template ...
<HierarchicalDataTemplate x:Key="treeHierarchicalDataTemplate"
ItemsSource="{Binding Path=ChildMeetingItems}">
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Red}" Value="True">
<Setter TargetName="img" Property="Image.Source" Value="pack://siteoforigin:,,,/images/bookRed.png"></Setter>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
<StackPanel
x:Name="treeViewItemPanel"
Background="Transparent"
Orientation="Horizontal">
<Image Width="16" Height="16" x:Name="img" Margin="0,0,4,0" Source="pack://siteoforigin:,,,/images/bookGreen.png"></Image>
<TextBlock Foreground="DarkGray" Text="{Binding DisplayIndex}" Margin="0,0,5,0"></TextBlock>
<TextBlock Text="{Binding Summary}"></TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
Qualquer ideia sobre o porquê de apenas o nó raiz em vez de nós filhos são selecionados quando eu botão direito do mouse?
Solução
Isso porque o ItemContainerStyle não é herdada por nós filho. Você precisa adicionar o mesmo EventSetter na ItemContainerStyle o seu HierarchicalDataTemplate.
<HierarchicalDataTemplate x:Key="treeHierarchicalDataTemplate"
ItemsSource="{Binding Path=ChildMeetingItems}">
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Red}" Value="True">
<Setter TargetName="img" Property="Image.Source" Value="pack://siteoforigin:,,,/images/bookRed.png"></Setter>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
<StackPanel
x:Name="treeViewItemPanel"
Background="Transparent"
Orientation="Horizontal">
<Image Width="16" Height="16" x:Name="img" Margin="0,0,4,0" Source="pack://siteoforigin:,,,/images/bookGreen.png"></Image>
<TextBlock Foreground="DarkGray" Text="{Binding DisplayIndex}" Margin="0,0,5,0"></TextBlock>
<TextBlock Text="{Binding Summary}"></TextBlock>
</StackPanel>
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<EventSetter Event="TreeViewItem.PreviewMouseRightButtonDown" Handler="trv_PreviewMouseRightButtonDown"/>
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
</HierarchicalDataTemplate>
Outras dicas
apenas comentar o e.Handler=true
do seu manipulador de eventos.
como este:
private void trv_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem item = sender as TreeViewItem;
if (item != null)
{
item.Focus();
// e.Handled = true;
}
}
Eu tive o mesmo problema - não poderia obter o item adequado árvore selecionada. E em vez de usar evento PreviewMouseRightButtonDown
eu usei mesmo evento de um StackPanel
que também armazena todos os dados necessária;
<StackPanel DataContext="{Binding}" MouseLeftButtonDown="StackPanel_MouseLeftButtonDown">
....
</StackPanel>
E o manipulador de eventos code-behind:
private void StackPanel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
StackPanel panel = sender as StackPanel;
if(panel==null)return;
MyTreeViewItem myClicked = panel.DataContext as MyTreeViewItem;
if (myClicked == null) return;
...
}
MyTreeViewItem
é o meu tipo personalizado para um de dados; myClicked
agora armazena a dados associados com o item da árvore clicado.
Espero que isso vai ajudar alguém como eu.