2012-09-14 72 views
0

我有同樣的問題,this question,我希望TreeViewItem仍然看起來主動選擇,當其上下文菜單顯示。但是,在我的樹中,每個級別都有不同類型的對象,所以我需要爲每個級別使用不同的ContextMenu。我正在使用HierachicalDataTemplate完成此操作。所以,我有以下XAML:WPF TreeViewItem上下文菜單Unhighlights項目與HierarchicalDataTemplate

<Window x:Class="Project.MainWindow"> 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Project" ContentRendered="Window_ContentRendered"> 
    <Grid> 
     <Grid.Resources> 
      <DataTemplate x:Key="VolumeTemplate"> 
       <StackPanel Orientation="Horizontal"> 
        <Image Source="{StaticResource VolumeIcon}" Margin="3,3,3,3" /> 
        <TextBlock Text="{Binding Path=Name}" Margin="3,3,3,3"> 
         <TextBlock.ContextMenu> 
          <ContextMenu> 
           <MenuItem Command="{Binding VolumeTestCommand}" 
              Header="VolumeTest" /> 
          </ContextMenu> 
         </TextBlock.ContextMenu> 
        </TextBlock> 
       </StackPanel> 
      </DataTemplate> 
      <HierachicalDataTemplate x:Key="ServerTemplate" 
            ItemsSource="{Binding Volumes}" 
            ItemTemplate="{StaticResource VolumeTemplate}"> 
       <StackPanel Orientation="Horizontal"> 
        <Image Source="{StaticResource ServerIcon}" Margin="3,3,3,3" /> 
        <TextBlock Text="{Binding Name}" Margin="3,3,3,3" > 
         <TextBlock.ContextMenu> 
          <ContextMenu> 
           <MenuItem Command="{Binding ServerTestCommand}" 
              Header="ServerTest" /> 
          </ContextMenu> 
         </TextBlock.ContextMenu> 
        </TextBlock> 
       </StackPanel> 
      </HierarchicalDataTemplate> 
     </Grid.Resources> 
     <TreeView HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
        ItemsSource="{Binding Servers}" Name="tvMain" 
        ItemTemplate="{StaticResource ServerTemplate}" 
        PreviewMouseRightButtonDown="tvMain_PreviewMouseRightButtonDown" /> 
    </Grid> 
</Window> 

而後面的代碼:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void Window_ContentRendered(object sender, EventArgs e) 
    { 
     //set DataContext here, based on a login dialog 
    } 

    static T VisualUpwardSearch<T>(DependencyObject source) where T : DependencyObject 
    { 
     DependencyObject returnVal = source; 

     while (returnVal != null && !(returnVal is T)) 
     { 
      if (returnVal is Visual || returnVal is Visual3D) 
      { 
       returnVal = VisualTreeHelper.GetParent(returnVal); 
      } 
      else 
      { 
       returnVal = LogicalTreeHelper.GetParent(returnVal); 
      } 
     } 

     return returnVal as T; 
    } 

    private void tvMain_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) 
    { 
     TreeViewItem treeViewItem = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject); 

     if(treeViewItem != null) 
     { 
      treeViewItem.IsSelected = true; 
      e.Handled = true; 
     } 
    } 
} 

我試圖從引用的問題的答案,但我認爲它不工作,因爲上下文菜單上的TextBlock而不是TreeViewItem。有沒有辦法將ContextMenu附加到DataTemplate中的TreeViewItem,或以其他方式解決此問題?

回答

0

我結束了不必創建附加屬性,這從將TextBlock到樹型視圖移動的上下文菜單:

public static readonly DependencyProperty StealContextMenuProperty = 
    DependencyProperty.RegisterAttached(
     "StealContextMenu", 
     typeof(bool), 
     typeof(ParentClass), 
     new UIPropertyMetadata(false, new PropertyChangedCallback(SCMChanged)) 
    ); 

public static bool GetStealContextMenu(FrameworkElement obj) 
{ 
    return (bool)obj.GetValue(StealContextMenuProperty); 
} 

public static void SetStealContextMenu(FrameworkElement obj, bool value) 
{ 
    obj.SetValue(StealContextMenuProperty, value); 
} 

public static void SCMChanged(object sender, DependencyPropertyChangedEventArgs e) 
{ 
    FrameworkElement fe = sender as FrameworkElement; 
    if (fe == null) return; 

    bool value = (bool)e.NewValue; 
    if (!value) return; 

    fe.Loaded += new RoutedEventHandler(fe_Loaded); 
} 

public static void fe_Loaded(object sender, RoutedEventArgs e) 
{ 
    FrameworkElement fe = (FrameworkElement)sender; 
    FrameworkElement child; 
    child = VisualDownwardSearch<FrameworkElement>(fe, x => x.ContextMenu != null); 
    if (child != null) 
    { 
     fe.ContextMenu = child.ContextMenu; 
     child.ContextMenu = null; 
    } 
} 

public static T VisualDownwardSearch<T>(T source, Predicate<T> match) 
    where T : DependencyObject 
{ 
    Queue<DependencyObject> queue = new Queue<DependencyObject>(); 
    queue.Enqueue(source); 
    while(queue.Count > 0) 
    { 
     DependencyObject dp = queue.Dequeue(); 

     if (dp is Visual || dp is Visual3D) 
     { 
      int childrenCount = VisualTreeHelper.GetChildrenCount(dp); 
      for (int i = 0; i < childrenCount; i++) 
      { 
       DependencyObject child = VisualTreeHelper.GetChild(dp, i); 
       if (child is T) 
       { 
        T tChild = (T)child; 
        if (match(tChild)) return tChild; 
       } 
       queue.Enqueue(child); 
      } 
     } 
     else 
     { 
      foreach (DependencyObject child in LogicalTreeHelper.GetChildren(dp)) 
      { 
       if (child is T) 
       { 
        T tChild = (T)child; 
        if (match(tChild)) return tChild; 
       } 
       queue.Enqueue(child);      
      } 
     } 
    } 
    return null;  
}