用奇怪的行为时,lambda表达式的WPF按钮单击事件 [英] Strange behavior when using lambda expression on WPF buttons click event

查看:159
本文介绍了用奇怪的行为时,lambda表达式的WPF按钮单击事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My problem is hard to explain, so I created an example to show here.

当显示在下面的例子中的WPF窗口,显示三个按钮,每一个具有不同的文本。

When the WPF window in the example below is shown, three buttons are displayed, each one with a different text.

当点击这些按钮的任何人,我认为它的文本应显示在消息中,而是,他们都显示相同的。消息,好像所有的人都用最后一个按钮的事件处理程序

When anyone of these buttons is clicked, I assume its text should be displayed in the message, but instead, all of them display the same message, as if all of them were using the event handler of the last button.

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



有谁知道什么是错的?

Does anyone know what is wrong?

推荐答案

这是因为闭包是如何评估的循环编译:

It is because of how closures are evaluated compiler in the loop:

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



编译器假定你将需要的背景下一个在封闭的,因为你正在使用 a.value中,所以它是创建使用值的1个lambda表达式。然而, A 的整个循环范围,因此它只会分配给它的最后一个值。

The compiler assumes that you will need the context of a in the closure, since you are using a.Value, so it is creating one lambda expression that uses the value of a. However, a has scope across the entire loop, so it will simply have the last value assigned to it.

为了解决这个问题,你需要复制 A 来循环中的变量,然后使用:

To get around this, you need to copy a to a variable inside the loop and then use that:

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

这篇关于用奇怪的行为时,lambda表达式的WPF按钮单击事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆