How can I access values on the UI thread?
I have no issues invoking actions on UI controls through BeginInvoke
and such, however, that's a void
method. I need to get a value from 开发者_如何学Pythona textbox for use in a different thread.
How can I accomplish this?
The simplest solution is to capture a local variable in a closure.
String text;
textBox.Invoke(() => text = textBox.Text);
The compiler will generate some code that is much like chibacity's solution - the local variable becomes a field of a compiler-generated class.
UPDATE
This does not work - the lambda expression is not assignable to Delegate
. This problem can be solved using an extension method.
internal void ExecuteOnOwningThread(this Control control, Action action)
{
if (control.InvokeRequired)
{
control.Invoke(action);
}
else
{
action();
}
}
The usage is then as follows.
String text;
textBox.ExecuteOnOwningThread(() => text = textBox.Text);
It is possible to stuff multiple statements into the lambda expression.
textBox.ExecuteOnOwningThread(() =>
{
DoStuff();
text = textBox.Text
DoOtherStuff();
});
But as chibacity already mentioned in a comment it may be better to explicitly write a method. Beyond a certain point using lambda expressions will adversely affect the readability of the code. And using lambda expressions is of course very prone to introducing repeated code.
The Control.Invoke() method returns the value of the invoked method. Which makes it easy:
string value = (string)this.Invoke(new Func<string>(() => textBox1.Text));
Or a bit more explicit:
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;
}
You can pass a delegate to Invoke that points to a method which can set an instance variable to hold the text value, e.g.
public Form1()
{
InitializeComponent();
Invoke(new Action(SetTextboxTextVariable));
}
private string _text;
private void SetTextboxTextVariable()
{
_text = txtBox.Text;
}
This covers the basic idea, synchronizing and notifying other threads is up to you. :)
Update
Or to do it in one step:
public Form1()
{
InitializeComponent();
string text = GetText();
}
private string GetText()
{
string text;
Invoke(new Action(text = txtBox.Text));
return text;
}
精彩评论