Самый простой подход - использовать событие всплытия MouseRightButtonDown вместо события туннелирования PreviewMouseRightButtonDown . Вы можете пометить перенаправленное событие как обработанное, установив для свойства Handled объекта EventArgs значение true, что остановит вызов других обработчиков событий. Таким образом, только самый глубокий TreeViewItem получит событие.
Если вы не можете использовать событие Preview, другой подход заключается в использовании свойства OriginalSource из EventArgs, чтобы найти элемент пользовательского интерфейса, который был фактически нажат. Вероятно, это будет ваш RichTextBox, поэтому вам нужно будет использовать метод для поиска визуального предка типа TreeViewItem. Есть пример метода, чтобы получить предка данного типа в http://www.wpftutorial.net/LogicalAndVisualTree.html:
public static class VisualTreeHelperExtensions
{
public static T FindAncestor<T>(DependencyObject dependencyObject)
where T : class
{
DependencyObject target = dependencyObject;
do
{
target = VisualTreeHelper.GetParent(target);
}
while (target != null && !(target is T));
return target as T;
}
}
Итак, вы можете вызвать ((DependencyObject)e.OriginalSource).FindAncestor<TreeViewItem>()
, чтобы найти TreeViewItem, по которому щелкнули. Если вы делаете это таким образом, вы должны присоединить обработчик событий к самому TreeView, а не к TreeViewItems. Это поймает щелчок в любом TreeViewItem, так как все они находятся внутри дерева, но он будет вызываться только один раз.
Редактировать: Как вы заметили, этот метод не работает, если целью является FrameworkContentElement, потому что это не Visual. Вместо этого вы можете сделать что-то вроде этого:
public static class VisualTreeHelperExtensions
{
public static T FindAncestor<T>(object dependencyObject)
where T : DependencyObject
{
var target = (DependencyObject)dependencyObject;
do
{
var visualParent = target is Visual ? VisualTreeHelper.GetParent(target) : null;
if (visualParent != null)
{
target = visualParent;
}
else
{
var logicalParent = LogicalTreeHelper.GetParent(target);
if (logicalParent != null)
{
target = logicalParent;
}
else
{
return null;
}
}
}
while (!(target is T));
return (T)target;
}
}
Тогда вы сможете получить TreeViewItem из OriginalSource, выполнив VisualTreeHelperExtensions.FindAncestor<TreeViewItem>(e.OriginalSource)
.