wpf MVVM中每个treeviewitem类型的不同上下文菜单

时间:2016-09-15 20:15:33

标签: c# wpf mvvm treeview

我能够成功实现TreeView,并且我使用Interface作为模板来显示Project / Folder / File的数据,就像Visual Studio的SolutionExplorer一样。我想根据项目类型将contextmenu添加到我的TreeViewItem,如下面的xaml文件中所述。但我无法根据TreeViewItem映射上下文菜单。我试着看看我是否可以使用有效的触发器,但我不知道如何根据TreeViewItem类型分配ContextMenu(例如我的情况下的Folder / File / Project)。

<!--<Trigger Property="IsSelected" Value="Folder">
                        <Setter Property="ContextMenu" Value="{StaticResource FolderMenu}" />
     </Trigger>-->

<Window x:Class="SimpleTreeWpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:SimpleTreeWpfApplication1"
    mc:Ignorable="d"

    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <local:TreeViewModel/>
</Window.DataContext>
<Grid>
    <TextBlock Text="Hierarchical root binding" Foreground="Red" Margin="10,20,0,0"/>
    <TreeView ItemsSource="{Binding TreeData}" Margin="10" Height="200">
        <TreeView.Resources>
            <!--  Begin Context Menu  -->
            <ContextMenu x:Key="ProjectMenu" >
                <MenuItem Command="{Binding AddFolder}" Header="Add Folder"/>
                <MenuItem Command="{Binding EditProject}" Header="Edit"/>
            </ContextMenu>
            <ContextMenu x:Key="FolderMenu" >
                <MenuItem Command="{Binding AddFolder}" Header="Add Folder"/>
                <MenuItem Command="{Binding AddFile}" Header="Add File"/>
            </ContextMenu>
            <ContextMenu x:Key="FileMenu" >
                <MenuItem Command="{Binding EditFile}" Header="Edit"/>                  
            </ContextMenu>
        </TreeView.Resources>
        <TreeView.ItemContainerStyle>

            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="ContextMenu" Value="{StaticResource FolderMenu}"/>
                <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                <Setter Property="FontWeight" Value="Normal" />
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="FontWeight" Value="Bold" />
                    </Trigger>

                </Style.Triggers>
            </Style>
        </TreeView.ItemContainerStyle>
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type local:INode}">
                <TreeViewItem Header="{Binding Label}"/>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>

</Grid>

界面和模型如下所示:

 public interface INode
  {
    string FullPath { get; }
    string Label { get; }
    List<INode> Children { get; }
 }


  public class Folder : INode
  {
    public List<INode> Children { get; set; }
    public string Label { get; set; }
    public string FullPath { get; set; }
    //custom values
    public Dictionary<string,string> MyFolderProperties { get; set; }

    //initialize default values
    public Folder()
    {
        Children = new List<INode>();
    }
}


 public class File : INode
  {
    public List<INode> Children { get; set; }
    public string Label { get; set; }
    public string FullPath { get; set; }

    //custom values
    public Dictionary<string,string> MyFileProperties { get; set; }
}


public class Project: INode
  {
    public List<INode> Children { get; set; }
    public string Label { get; set; }
    public string FullPath { get; set; }

    public List<String> ProjectTypeValuesDb { get; set; }

    //initialize default values
    public Project()
    {
        Children = new List<INode>();
    }
}



 //Viewmodel code
 public class TreeViewModel : INotifyPropertyChanged
 {
    public TreeViewModel()
    {

        //initialize and add
        m_folders = new List<INode>();
        TreeData = m_folders;
        //add Root items
        TreeData.Add(new Folder { Label = "Folder1", FullPath = @"C:\dummy1" });
        TreeData.Add(new Folder { Label = "Folder2", FullPath = @"C:\dummy2" });
        TreeData.Add(new Folder { Label = "Folder3", FullPath = @"C:\dummy3" });
        TreeData.Add(new Folder { Label = "Folder4", FullPath = @"C:\dummy4" });
        //Folders.Add(new File { Label = "File1.txt", FullPath = @"C:\File1.txt" });

        //add sub items
        TreeData[0].Children.Add(new Folder { Label = "Folder11", FullPath = @"C:\dummy11" });
        TreeData[0].Children.Add(new Folder { Label = "Folder12", FullPath = @"C:\dummy12" });
        TreeData[0].Children.Add(new Folder { Label = "Folder13", FullPath = @"C:\dummy13" });
        TreeData[0].Children.Add(new Folder { Label = "Folder14", FullPath = @"C:\dummy14" });

        TreeData[0].Children.Add(new File { Label = "File1.txt", FullPath = @"C:\File1.txt" });
        TreeData[0].Children.Add(new File { Label = "File2.txt", FullPath = @"C:\File1.txt" });
        TreeData[0].Children.Add(new File { Label = "File3.txt", FullPath = @"C:\File1.txt" });

    }



    bool _isExpanded = false;
    bool _isSelected = false;
    #region IsExpanded
    /// <summary>
    /// Gets/sets whether the TreeViewItem 
    /// </summary>
    public bool IsExpanded
    {
        get { return _isExpanded; }
        set
        {
            if (value != _isExpanded)
            {
                _isExpanded = value;
                this.NotifiyPropertyChanged("IsExpanded");
            }

            // Expand all the way up to the root.
            //if (_isExpanded && _parent != null)
            //    _parent.IsExpanded = true;
        }
    }

#endregion // IsExpanded

    #region IsSelected

    /// <summary>
    /// Gets/sets whether the TreeViewItem 
    /// associated with this object is selected.
    /// </summary>
    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (value != _isSelected)
            {
                _isSelected = value;
                this.NotifiyPropertyChanged("IsSelected");
            }
        }
    }

    #endregion // IsSelected

    private List<INode> m_folders;
    public List<INode> TreeData
    {
        get { return m_folders; }
        set
        {
            m_folders = value;
            NotifiyPropertyChanged("Folders");
        }
    }

    void NotifiyPropertyChanged(string property)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

1 个答案:

答案 0 :(得分:0)

这很简单HierarchicalDataTemplate。只需将其克隆为DataType="{x:Type local:Folder}"DataType="{x:Type local:File}"等,并为每个模板中的ContextMenu提供相应的TreeViewItem。您可以在TreeView.Resources而不是ItemTemplate属性中定义模板。