一个ICommands循环

时间:2017-04-11 06:14:00

标签: c# wpf

我有一个ICommands循环(好吧,RelayCommand继承自ICommand),我不知道如何向每个ICommand提供信息。

我实际上在做的是创建一个WPF上下文菜单,每个菜单项都有一个ICommand。每个菜单项都需要做不同的事情。它需要将点击的项目(角色)添加到一组项目(场景)。

如果我展示循环本身,我会更清楚:

foreach (Scene s in Database.Instance.Scenes)
{
    SceneAddMenu.Add(new ContextMenuVM()
    {
        DisplayName = s.SceneName,
        ContextMenuCommand = new RelayCommand(
        () =>
        {
            MessageBox.Show("Clicked " + s.SceneID.ToString());

        })
    });
}

ContextMenuVM包含一个String(菜单项显示文本)和ContextMenuCommand,它是一个RelayCommand(继承自ICommand)。

目前,代码始终使用列表中的最终场景ID运行。我认为这是因为表达式是在运行时进行评估的(我可能完全错了),所以它总是在循环结束时。

我想要的是从每个循环外部(场景')获取信息到循环内部。

我对此问题的了解不够充分。我已经搜索了ICommand循环'直到我在谷歌面前脸红,但我不认为这些是我问题的正确关键词。

任何帮助都会受到赞赏,即使只是用于搜索的正确术语。

2 个答案:

答案 0 :(得分:0)

是的!这是捕获变量的问题。所有内存引用都更新为保持的最后一个值变量。你将不得不稍微调整一下,但这里有一个想法可以采取/尝试的替代方案。

public class Program {
    public void Main() {
        var commands = new List<MenuCommand>();
        // Add commands
        for (int i = 1; i <= 3; i++) {
            commands.Add(new MenuCommand(MenuItemAction) { SceneId = i });
        }
        // Exec commands - Test
        foreach (var cmd in commands) {
            cmd.Execute(cmd.SceneId);
        }
    }

    public void MenuItemAction(object sceneId) {
        Console.WriteLine("Clicked: " + sceneId);
    }
}

public class MenuCommand : RelayCommand {
    public int SceneId { get; set; }

    public MenuCommand(Action<object> action) : 
        base(action) { 
    }
}

public class RelayCommand : ICommand {
    private Action<object> action;

    public RelayCommand(Action<object> action) {
        this.action = action;
    }

    public virtual void Execute(object parameter) {
        this.action(parameter);
    }
}

答案 1 :(得分:0)

在循环中创建SceneID的副本:

foreach (Scene s in Database.Instance.Scenes)
{
    int id = s.SceneID;
    SceneAddMenu.Add(new ContextMenuVM()
    {
        DisplayName = s.SceneName,
        ContextMenuCommand = new RelayCommand(
        () =>
        {
            MessageBox.Show("Clicked " + id.ToString());

        })
    });
}