2010-05-30 74 views
3

我没有问题通过BeginInvoke等UI控件调用操作,但是,这是一个void方法。我需要从一个文本框中获取一个值用于不同的线程。如何访问UI线程中的值?

我该如何做到这一点?

回答

4

最简单的办法是捕捉到一个局部变量中关闭。

String text; 
textBox.Invoke(() => text = textBox.Text); 

编译器将生成一些代码,很像chibacity的溶液 - 局部变量变为编译器生成的类的字段。

UPDATE

这不起作用 - 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表达式当然很容易引入重复的代码。

+0

虽然具有一个班轮是可爱的,最终你会比例如设置变量做更多告诉另一个线程有一些数据准备好。有一个方法来填补这是进路。 – 2010-05-30 00:32:54

+0

我绝对同意你 - 对于不重复多次的一个,两个或三个语句,我会考虑使用lambda表达式,但除此之外,使用单独的方法会产生更好的代码。 – 2010-05-30 00:54:52

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

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