wpf MVVM中每个树视图类型的不同上下文菜单

本文关键字:上下文 菜单 类型 视图 MVVM wpf | 更新日期: 2023-09-27 18:07:14

我能够成功地实现TreeView,我使用接口作为模板来显示项目/文件夹/文件的数据,就像Visual Studio的SolutionExplorer一样。我想添加上下文菜单到我的TreeViewItem基于项目类型描述在我的xaml文件下面。但是我不能基于TreeViewItem来映射上下文菜单。我试着看看我是否可以使用触发器工作,但我不知道如何分配基于TreeViewItem类型的上下文菜单(例如:文件夹/文件/项目)。

<!--<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;
}

wpf MVVM中每个树视图类型的不同上下文菜单

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