c# - 在 WPF 按钮单击事件上使用 lambda 表达式时出现奇怪的行为

标签 c# wpf events lambda

我的问题很难解释,所以我创建了一个示例在这里展示。

当显示下例中的 WPF 窗口时,会显示三个按钮,每个按钮都有不同的文本。

当单击这些按钮中的任何一个时,我认为其文本应该显示在消息中,但相反,所有这些按钮都显示相同的消息,就好像它们都使用最后一个按钮的事件处理程序一样。

public partial class Window1 : Window {
    public Window1() {
        InitializeComponent();
        var stackPanel = new StackPanel();
        this.Content = stackPanel;
        var n = new KeyValuePair<string, Action>[] { 
            new KeyValuePair<string, Action>("I", () => MessageBox.Show("I")), 
            new KeyValuePair<string, Action>("II", () => MessageBox.Show("II")), 
            new KeyValuePair<string, Action>("III", () => MessageBox.Show("III"))
        };
        foreach (var a in n) {
            Button b = new Button();
            b.Content = a.Key;
            b.Click += (x, y) => a.Value();
            stackPanel.Children.Add(b);
        }
    }
}

有人知道哪里出了问题吗?

最佳答案

这是因为编译器在循环中评估闭包的方式:

foreach (var a in n) {
    Button b = new Button();
    b.Content = a.Key;
    b.Click += (x, y) => a.Value();
    stackPanel.Children.Add(b);
}

编译器假定您在闭包中需要 a 的上下文,因为您使用的是 a.Value,因此它会创建一个使用a 的值。但是,a 的作用域涵盖整个循环,因此它只会分配最后一个值。

要解决这个问题,您需要将 a 复制到循环内的变量,然后使用它:

foreach (var a in n) {
    Button b = new Button();
    b.Content = a.Key;

    // Assign a to another reference.
    var a2 = a;

    // Set click handler with new reference.
    b.Click += (x, y) => a2.Value();
    stackPanel.Children.Add(b);
}

关于c# - 在 WPF 按钮单击事件上使用 lambda 表达式时出现奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/566687/

相关文章:

c# - Entity Framework 6 渴望加载具有许多子项和子项的大对象

wpf - 如何处理 KeyDown 事件的 WPF TextBox "knows"

wpf - 排序不适用于 WPF DataGrid 模板化列?

linux - 无法让 eventfd 与 epoll 一起工作

jquery - 如何在不导入整个移动驱动 JavaScript 框架的情况下使用触摸事件?

c# - 在没有 "Time.timeScale = 0"的情况下暂停 Unity 游戏

c# - API 路由 : Multiple operations with path

.net - Winform - 这是用户控件最后触发的事件

c# - 使用 FTP 传输文件

WPF - 在没有键的情况下在 ResourceDictionary 中定义 DataTemplate