ContextMenu基于绑定对象中的枚举

时间:2014-09-18 13:16:11

标签: c# wpf data-binding enums triggers

我的Node课程:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

namespace FrontEnd
{
    public enum NodeType
    {
        SQLite,
        Database,
        TableCollection,
        ViewCollection,
        IndexCollection,
        TriggerCollection,
        ColumnCollection,
        Table,
        View,
        Column,
        Index,
        Trigger
    }

    public class Node
    {
        public string Title { get; protected set; }
        public NodeType Type { get; protected set; }
        public ObservableCollection<Node> Nodes { get; set; }

        public Node(string title, NodeType type)
        {
            this.Title = title;
            this.Type = type;
            this.Nodes = new ObservableCollection<Node>();
        }
    }
}

我的XAML:

    <TreeView Name="dbTree" Padding="0,5,0,0">
        <TreeView.Resources>
            <ContextMenu x:Key="ScaleCollectionPopup">
                <MenuItem Header="New Scale..."/>
            </ContextMenu>
            <ContextMenu x:Key="ScaleItemPopup">
                <MenuItem Header="Remove Scale"/>
            </ContextMenu>
        </TreeView.Resources>
        <TreeView.ItemContainerStyle>
            <Style TargetType="TreeViewItem">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Type, RelativeSource={RelativeSource Self}}" Value="NodeType.Column">
                        <Setter Property="ContextMenu" Value="{StaticResource ScaleItemPopup}" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TreeView.ItemContainerStyle>
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
                <StackPanel Orientation="Horizontal" Margin="0,0,0,4">
                    <Image Source="{Binding Converter={StaticResource StringToImageConverter}}" />
                    <TextBlock Text="{Binding Title}" Padding="5,0,0,0" />
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>

我想要实现和失败的是根据绑定的ContextMenu类的Type属性决定使用Node

如果它是一个表或视图我想显示&#34; SELECT 1000 ROWS&#34; &安培; &#34; SHOW CREATE SQL&#34;,对于其他类型,我想定义其他选项。

达到预期效果的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

当每个节点的视图模型生成上下文菜单时,我更喜欢以mvvm样式执行此操作。请参阅以下示例:

查看部分:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:wpfApplication1="clr-namespace:WpfApplication1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525"
    d:DataContext="{d:DesignInstance wpfApplication1:ViewModel}">
<Grid>
    <TreeView ItemsSource="{Binding Path=Nodes}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
                <StackPanel>
                    <StackPanel.ContextMenu>
                        <ContextMenu ItemsSource="{Binding ContextMenu}">
                            <ContextMenu.Resources>
                                <Style TargetType="MenuItem">
                                    <Setter Property="Command" Value="{Binding Command}"/>
                                </Style>
                            </ContextMenu.Resources>
                            <ContextMenu.ItemTemplate>
                                <HierarchicalDataTemplate ItemsSource="{Binding Items}">
                                    <TextBlock Text="{Binding Title}"/>
                                </HierarchicalDataTemplate>
                            </ContextMenu.ItemTemplate>
                        </ContextMenu>
                    </StackPanel.ContextMenu>
                    <TextBlock Text="{Binding Title}"/>
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</Grid>

查看模型部分:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }
}

public class MenuItem
{
    public MenuItem()
    {
        Items = new ObservableCollection<MenuItem>();
    }

    public string Title { get; set; }
    public ICommand Command { get; set; }
    public ObservableCollection<MenuItem> Items { get; private set; }
}

public class ViewModel
{
    public ViewModel()
    {
        Nodes = new ObservableCollection<Node>
        {
            new Node("MSSQL", NodeType.Database,
                new Node("Customers", NodeType.Table)),
            new Node("Oracle", NodeType.Database)
        }; 
    }

    public ObservableCollection<Node> Nodes { get; set; }
}

public enum NodeType
{
    Database,
    Table,
}

public class Node
{
    public string Title { get; protected set; }
    public NodeType Type { get; protected set; }
    public ObservableCollection<Node> Nodes { get; set; }

    public Node(string title, NodeType type, params Node[] nodes)
    {
        this.Title = title;
        this.Type = type;
        this.Nodes = new ObservableCollection<Node>();
        if (nodes != null)
            nodes.ToList().ForEach(this.Nodes.Add);
    }

    public IEnumerable<MenuItem> ContextMenu
    {
        get { return createMenu(this); }
    }

    private static IEnumerable<MenuItem> createMenu(Node node)
    {
        switch (node.Type)
        {
            case NodeType.Database:
                return new List<MenuItem>
                {
                    new MenuItem {Title = "Create table...",  Command = new RelayCommand(o => MessageBox.Show("Table created"))}
                };
            case NodeType.Table:
                return new List<MenuItem>
                {
                    new MenuItem {Title = "Select..."},
                    new MenuItem {Title = "Edit..."}
                };
            default:
                return null;
        }
    }
}

public class RelayCommand : ICommand
{
    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    #endregion // Fields

    #region Constructors

    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors

    #region ICommand Members

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    #endregion // ICommand Members
}

(你可以使用任何实现ICommand接口,RelayCommand就是其中之一) 您可以在Node类或IContextMenuBuilder服务中生成可以传递给Node构造函数的菜单项。