В WPF, как мне выбрать элемент treeview под моим курсором при щелчке правой кнопкой мыши?
-
18-09-2019 - |
Вопрос
В WPF, когда я щелкаю правой кнопкой мыши по элементу treeview, я бы хотел, чтобы он был выбран / активирован перед отображением контекстного меню.
Это звучит довольно просто, но включение hierachicalDataTemplate немного усложняет ситуацию.
У меня есть следующий вид дерева:
<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>
А вот и мой обработчик событий...
private void trv_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem item = sender as TreeViewItem;
if (item != null)
{
item.Focus();
e.Handled = true;
}
}
Обратите внимание, как я добавляю EventSetter выше.Это ПОЧТИ сработало.Но он выбирает только узел treeview корневого уровня (т.е.корневой родительский узел, на котором я щелкаю правой кнопкой мыши).Это может быть из-за моего иерархического шаблона данных?Этот шаблон может содержать дочерние элементы ТОГО ЖЕ ТИПА.
Вот мой иерархический шаблон данных...
<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 не наследуется дочерними узлами.Вам нужно добавить тот же EventSetter в ItemContainerStyle вашего 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>
Другие советы
просто прокомментируйте e.Handler=true
из вашего обработчика событий.
вот так:
private void trv_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem item = sender as TreeViewItem;
if (item != null)
{
item.Focus();
// e.Handled = true;
}
}
У меня была та же проблема - не удалось получить правильно выбранный элемент дерева.И вместо того, чтобы использовать PreviewMouseRightButtonDown
событие, которое я использовал в том же событии StackPanel
который также хранит все необходимые данные:
<StackPanel DataContext="{Binding}" MouseLeftButtonDown="StackPanel_MouseLeftButtonDown">
....
</StackPanel>
И код обработчика событий, лежащий в основе:
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
является ли мой пользовательский тип для данных; myClicked
теперь сохраняет данные, связанные с выбранным элементом дерева.Надеюсь, это поможет кому-то вроде меня.