【问题标题】:Programmatically add a context menu whose Click handler knows which item was right-clicked以编程方式添加一个上下文菜单,其 Click 处理程序知道哪个项目被右键单击
【发布时间】:2016-10-27 07:06:38
【问题描述】:

我正在动态生成一个树 (TreeViewItems),并希望为树中的每个项目添加相同的上下文菜单。因为所有的上下文菜单都是相同的,所以我想我可以制作一个,并将其应用于每个TreeViewItem。 (也许这是个坏主意?)只要Click 处理程序可以确定打开了哪个TreeViewItem 的上下文菜单,这似乎应该可以工作。

我尝试结合来自here(获取右键单击的对象)和here(以编程方式添加绑定)的 SO 答案并想出了这个:

ContextMenu carContextMenu;

public MainWindow()
{
    InitializeComponent();
    Initialize();
    ConstructTree();
}

void ConstructTree()
{
    string[] carNames = {"Mustang", "Viper", "Jetta"};

    foreach (string car in carNames)
    {
        TreeViewItem carNode = new TreeViewItem();
        carNode.Header = car;
        carNode.ContextMenu = carContextMenu;

        CarTree.Items.Add(carNode);
    }
}

void Initialize()
{
    carContextMenu= new ContextMenu();
    MenuItem newQuery = new MenuItem();
    newQuery.Header = "Drive car...";

    Binding b = new Binding("Parent");
    b.RelativeSource = RelativeSource.Self;

    newQuery.SetBinding(MenuItem.CommandParameterProperty, b);
    newQuery.Click += NewQuery_Click;

    carContextMenu.Items.Add(newQuery);
}

void NewQuery_Click(object sender, RoutedEventArgs e)
{
    MenuItem mi = sender as MenuItem;
    if (mi != null)
    {
        ContextMenu cm = mi.CommandParameter as ContextMenu; // *****
        if (cm != null)
        {
            TreeViewItem node = cm.PlacementTarget as TreeViewItem;
            if (node != null)
            {
                Console.WriteLine(node.Header); // car name, ideally
            }
        }
    }
}

在运行时,当它到达带星号的行时,mi.CommandParameter 为空,因此它会跳过该方法的其余部分。我的方法是怎么回事?老实说,考虑到您想知道单击什么的频率,我有点惊讶右键单击的项目不是事件处理程序参数的固有部分。右键单击树项时不需要选择它们,因此检查这不是一种可靠的方法......而且它只是一个 hacky 解决方法。

谢谢!

【问题讨论】:

  • 您是否熟悉如何使用Sender 来确定或获取被点击对象的名称..?
  • 我猜不是?我浏览了MenuItemsender 的类型)属性,没有发现任何有用的东西。与 RoutedEventArgs 相同。也许我将同一个 ContextMenu 对象附加到多个 TreeViewItems 的事实搞砸了?
  • 您可以检查发件人 ID,这将是我这样做的名称,以确定用户当前在运行时单击的菜单项,方法是将所有菜单项连接到同一事件,然后使用switch / case 来确定点击了哪个菜单项
  • 我将发布一个示例,说明我是如何做到的,并且每个 ToolStripMenItem 事件都指向同一个
  • 你的 XAML 是什么样子的,你有类似的东西吗CommandParameter="{Binding RelativeSource={RelativeSource Self}}">

标签: c# .net wpf


【解决方案1】:

当然,事实证明我把事情复杂化了,我关注的链接要么不正确、过时,要么(很可能)我误读了他们场景的某些部分,并且有些东西实际上并不适用对我来说。

我不需要对MenuItem 本身进行任何绑定,并且应该一直在查看myMenuItem.Parent.PlacementTarget。工作代码如下:

void Initialize()
{
    carContextMenu= new ContextMenu();
    MenuItem newQuery = new MenuItem();
    newQuery.Header = "Drive car...";

    newQuery.Click += NewQuery_Click;

    carContextMenu.Items.Add(newQuery);
}

void NewQuery_Click(object sender, RoutedEventArgs e)
{
    MenuItem mi = sender as MenuItem;
    if (mi != null)
    {
        ContextMenu cm = mi.Parent as ContextMenu;
        if (cm != null)
        {
            TreeViewItem node = cm.PlacementTarget as TreeViewItem;
            if (node != null)
            {
                Console.WriteLine(node.Header);
            }
        }
    }
}  

【讨论】:

    猜你喜欢
    • 2010-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多