2017-02-18 20 views
0

我有一個帶有heterogeneuos節點類型的TreeView。每個節點類型都使用HierarchicalDataTemplate在XAML中進行配置。在WPF中的整個TreeViewItem行上顯示ContextMenu

某些節點有一個ContextMenu,它取決於節點的類型。 ContextMenus被定義爲XAML中的靜態資源,並被附加到HierarchicalDataTemplate中的DockPanel。

另外,我在下面的StackOverflow問題https://stackoverflow.com/a/672123/1626109中使用了由Bendewey描述的TreeViewItem的ControlTemplate。這個ControlTemplate是這樣定義的,當完整的TreeViewItem被選中時被高亮顯示。 左鍵單擊該行的任何部分,選擇該項目。

相比之下,在HierarchicalDataTemplate中定義的上下文菜單僅適用於該行的右側部分。

我正在尋找一種方法來配置ContextMenus,以便它們也可以在整個行中使用。

這似乎需要將上下文菜單附加到ControlTemplate中的一個元素上,並使用TemplateBinding來定義HierarchicalDataTemplate中的某些元素,但我無法弄清楚如何去做。

順便說一句,在Visual Studio中的解決方案資源管理器正是這種行爲。上下文菜單取決於節點類型,並且在完整項目上可用,包括展開/摺疊按鈕的左側。

回答

1

(編輯),您需要在TreeViewItem風格擺脫Grid的兩列:

<Window.Resources> 
    <local:LeftMarginMultiplierConverter Length="19" x:Key="lengthConverter" /> 
    <SolidColorBrush x:Key="GlyphBrush" Color="#444" /> 
    <Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton"> 
     <Setter Property="Focusable" Value="False"/> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="ToggleButton"> 
        <Grid Width="15" Height="13" 
     Background="Transparent"> 
         <Path x:Name="ExpandPath" 
     HorizontalAlignment="Left" 
     VerticalAlignment="Center" 
     Margin="1,1,1,1" 
     Fill="{StaticResource GlyphBrush}" 
     Data="M 4 0 L 8 4 L 4 8 Z"/> 
        </Grid> 
        <ControlTemplate.Triggers> 
         <Trigger Property="IsChecked" 
      Value="True"> 
          <Setter Property="Data" 
      TargetName="ExpandPath" 
      Value="M 0 4 L 8 4 L 4 8 Z"/> 
         </Trigger> 
        </ControlTemplate.Triggers> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
    <Style x:Key="TreeViewItemFocusVisual"> 
     <Setter Property="Control.Template"> 
      <Setter.Value> 
       <ControlTemplate> 
        <Border> 
         <Rectangle Margin="0,0,0,0" 
      StrokeThickness="5" 
      Stroke="Black" 
      StrokeDashArray="1 2" 
      Opacity="0"/> 
        </Border> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
    <Style x:Key="{x:Type TreeViewItem}" 
TargetType="{x:Type TreeViewItem}"> 
     <Setter Property="Background" 
    Value="Transparent"/> 
     <Setter Property="HorizontalContentAlignment" 
    Value="{Binding Path=HorizontalContentAlignment, 
      RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/> 
     <Setter Property="VerticalContentAlignment" 
    Value="{Binding Path=VerticalContentAlignment, 
      RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/> 
     <Setter Property="Padding" 
    Value="1,0,0,0"/> 
     <Setter Property="Foreground" 
    Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> 
     <Setter Property="FocusVisualStyle" 
    Value="{StaticResource TreeViewItemFocusVisual}"/> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type TreeViewItem}"> 
        <ControlTemplate.Resources> 
         <local:LeftMarginMultiplierConverter Length="19" x:Key="lengthConverter" /> 
        </ControlTemplate.Resources> 
        <StackPanel> 
         <Border Name="Bd" 
      Background="{TemplateBinding Background}" 
      BorderBrush="{TemplateBinding BorderBrush}" 
      BorderThickness="{TemplateBinding BorderThickness}" 
      Padding="{TemplateBinding Padding}"> 
          <Grid> 
           <ToggleButton Panel.ZIndex="2" x:Name="Expander" 
               HorizontalAlignment="Left" 
       Style="{StaticResource ExpandCollapseToggleStyle}" 
       IsChecked="{Binding Path=IsExpanded, 
          RelativeSource={RelativeSource TemplatedParent}}" 
       ClickMode="Press" 
               Margin="{Binding Converter={StaticResource lengthConverter}, ConverterParameter=0, 
          RelativeSource={RelativeSource TemplatedParent}}"/> 

           <ContentPresenter x:Name="PART_Header" ContentSource="Header" 
        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"> 
           </ContentPresenter> 
          </Grid> 
         </Border> 
         <ItemsPresenter x:Name="ItemsHost" /> 
        </StackPanel> 
        <ControlTemplate.Triggers> 
         <Trigger Property="IsExpanded" 
      Value="false"> 
          <Setter TargetName="ItemsHost" 
      Property="Visibility" 
      Value="Collapsed"/> 
         </Trigger> 
         <Trigger Property="HasItems" 
      Value="false"> 
          <Setter TargetName="Expander" 
      Property="Visibility" 
      Value="Hidden"/> 
         </Trigger> 
         <MultiTrigger> 
          <MultiTrigger.Conditions> 
           <Condition Property="HasHeader" 
       Value="false"/> 
           <Condition Property="Width" 
       Value="Auto"/> 
          </MultiTrigger.Conditions> 
          <Setter TargetName="PART_Header" 
      Property="MinWidth" 
      Value="75"/> 
         </MultiTrigger> 
         <MultiTrigger> 
          <MultiTrigger.Conditions> 
           <Condition Property="HasHeader" 
       Value="false"/> 
           <Condition Property="Height" 
       Value="Auto"/> 
          </MultiTrigger.Conditions> 
          <Setter TargetName="PART_Header" 
      Property="MinHeight" 
      Value="19"/> 
         </MultiTrigger> 
         <Trigger Property="IsSelected" 
      Value="true"> 
          <Setter TargetName="Bd" 
      Property="Background" 
      Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/> 
          <Setter Property="Foreground" 
      Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/> 
         </Trigger> 
         <MultiTrigger> 
          <MultiTrigger.Conditions> 
           <Condition Property="IsSelected" 
       Value="true"/> 
           <Condition Property="IsSelectionActive" 
       Value="false"/> 
          </MultiTrigger.Conditions> 
          <Setter TargetName="Bd" 
      Property="Background" 
      Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/> 
          <Setter Property="Foreground" 
      Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> 
         </MultiTrigger> 
         <Trigger Property="IsEnabled" 
      Value="false"> 
          <Setter Property="Foreground" 
      Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> 
         </Trigger> 
        </ControlTemplate.Triggers> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</Window.Resources> 

然而,這會扭曲頭項安排。因此,你需要調整保證金的HierarchicalDataTemplate部分:

<TreeView Margin="50" HorizontalContentAlignment="Stretch" DataContext="{Binding}" ItemsSource="{Binding Models}"> 
    <TreeView.ItemTemplate> 
     <HierarchicalDataTemplate DataType="{x:Type local:Model}" ItemsSource="{Binding Models}"> 
      <Border Background="Transparent"> 
       <TextBlock Margin="{Binding Converter={StaticResource lengthConverter}, ConverterParameter=1, 
                   RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TreeViewItem}}" 
          Text="{Binding Name}" /> 
       <Border.ContextMenu> 
        <ContextMenu> 
         <MenuItem Header="dddd"/> 
        </ContextMenu> 
       </Border.ContextMenu> 
      </Border> 
     </HierarchicalDataTemplate> 
    </TreeView.ItemTemplate> 
</TreeView> 

請注意,您應該調整轉換器能夠採取必要的額外保證金到:

public class LeftMarginMultiplierConverter : IValueConverter 
{ 
    public double Length { get; set; } 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     var item = value as TreeViewItem; 
     if (item == null) 
      return new Thickness(0); 
     int extra = int.Parse(parameter.ToString()); 
     var t = item.GetDepth(); 
     return new Thickness(Length * (item.GetDepth() + extra), 0, 0, 0); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new System.NotImplementedException(); 
    } 
} 

如果轉換器參數爲1 ,它會在物品的深度添加一個點。我用它作爲標題的一部分。

另一種方法可能是將DataTemplate添加到TreeViewItemStyleContentPresenter。雖然我不知道如何綁定ContextMenu,但我更喜歡這個。

+0

這不是問題所在。 TreeViewItem的ControlTemplate根據樹的深度定義了一個邊距,然後是展開/摺疊按鈕,然後是DataTemplate所在的ContentPresenter。我需要整行上下文菜單,因此需要在ControlTemplate中(邊界上,網格上或某個新元素上)定義,但是綁定到HierarchicalDataTemplate中的定義。 –

+0

沒關係。查看編輯。 – Ron

+0

謝謝,這是有效的。關於將縮進的責任下移到DataTemplates和HierarchicalDataTemplates中,我感覺有點不好。我的直覺反應說它不屬於那裏。 (但是,您可能會認爲ContextMenu不屬於該行的該部分。) –