如何在UI线程上访问值?

3

我在UI控件上使用BeginInvoke等方法执行操作没有问题,但这是一个void方法。我需要从文本框中获取值以在不同的线程中使用。

我该如何实现这一点?

3个回答

5
最简单的解决方案是在闭包中捕获一个本地变量。
String text;
textBox.Invoke(() => text = textBox.Text);

编译器将生成一些类似于chibacity方案的代码 - 局部变量成为编译器生成类的字段。
更新
这种方法不起作用- lambda表达式不能分配给Delegate。可以使用扩展方法解决此问题。
internal void ExecuteOnOwningThread(this Control control, Action action)
{
    if (control.InvokeRequired)
    {
        control.Invoke(action);
    }
    else
    {
        action();
    }
}

使用方法如下。
String text;
textBox.ExecuteOnOwningThread(() => text = textBox.Text);

lambda表达式可以包含多个语句。

textBox.ExecuteOnOwningThread(() =>
{
    DoStuff();
    text = textBox.Text
    DoOtherStuff();
});

但是,正如chibacity在评论中提到的,最好明确编写一个方法。过度使用Lambda表达式会影响代码的可读性。而且,使用Lambda表达式很容易引入重复的代码。


虽然一行代码很简洁,但最终你会做更多的事情,比如告诉另一个线程有一些数据准备好了。拥有一个方法来处理这个问题是正确的方式。 - Tim Lloyd
我完全同意你的观点 - 对于只有一两个或者三个不重复多次的语句,我会考虑使用lambda表达式,但是除此之外,使用单独的方法可以得到更好的代码。 - Daniel Brückner

4

Control.Invoke() 方法返回被调用方法的值,这使得它变得简单:

        string value = (string)this.Invoke(new Func<string>(() => textBox1.Text));

或者更加明确一些:
    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
        var dlg = new Func<string>(GetText);
        string value = (string)this.Invoke(dlg);
    }
    private string GetText() {
        return textBox1.Text;
    }

0

您可以传递一个委托到Invoke,该委托指向一个方法,该方法可以设置一个实例变量来保存文本值,例如:

    public Form1()
    {
        InitializeComponent();

        Invoke(new Action(SetTextboxTextVariable));
    }

    private string _text;

    private void SetTextboxTextVariable()
    {
        _text = txtBox.Text;
    } 

这涵盖了基本思想,同步和通知其他线程由您决定。 :)

更新

或者可以一步完成:

    public Form1()
    {
        InitializeComponent();

        string text = GetText();
    }

    private string GetText()
    {
        string text;

        Invoke(new Action(text = txtBox.Text));

        return text;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接