In WPF, come faccio a selezionare la voce ad albero sotto il cursore sul tasto destro del mouse?
-
18-09-2019 - |
Domanda
In WPF, quando right-click su un elemento TreeView vorrei che fosse selezionato / attivato prima di mostrare il menu di contesto.
Ciò suona abbastanza semplice, ma l'inclusione di un hierachicalDataTemplate complica le cose un po '.
Ho il seguente 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 qui è il mio gestore di eventi ...
private void trv_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem item = sender as TreeViewItem;
if (item != null)
{
item.Focus();
e.Handled = true;
}
}
Si noti come posso aggiungere un EventSetter sopra. Questo funziona quasi. Ma seleziona solo il nodo treeview livello principale (cioè il genitore radice del nodo su cui destro). Questo può essere a causa del mio modello dati gerarchici? Questo modello può contenere figli dello stesso TIPO.
Ecco il mio modello di dati gerarchici ...
<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>
Qualche idea sul perché solo il nodo radice invece di nodi figli vengono selezionati quando right-click?
Soluzione
Questo perché l'ItemContainerStyle non è ereditata dai nodi figlio. È necessario aggiungere lo stesso EventSetter sul ItemContainerStyle o la vostra 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>
Altri suggerimenti
solo commentare il e.Handler=true
dal vostro gestore di eventi.
in questo modo:
private void trv_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem item = sender as TreeViewItem;
if (item != null)
{
item.Focus();
// e.Handled = true;
}
}
Ho avuto lo stesso problema - non ha potuto ottenere l'apposita voce dell'albero selezionato. E invece di utilizzare evento PreviewMouseRightButtonDown
ho usato lo stesso caso di StackPanel
che memorizza tutti i dati anche necessario:
<StackPanel DataContext="{Binding}" MouseLeftButtonDown="StackPanel_MouseLeftButtonDown">
....
</StackPanel>
E il gestore di eventi 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
è il mio tipo personalizzato per un dato; myClicked
ora memorizza un dato associato all'elemento albero fatto clic.
Spero che vi aiuterà a uno come me.