如何更新从C#中的另一个线程的GUI? [英] How to update the GUI from another thread in C#?
问题描述
什么是更新标签最简单的方式
从另一个线程?
What is the simplest way to update a Label
from another thread?
我有一个表格
在线程1
,从我开始另一个线程(线程2
)。虽然线程2
正在处理一些文件,我想更新表格上一个
标签
code>与当前状态线程2
的工作。
I have a Form
on thread1
, from that I'm starting another thread (thread2
). While thread2
is processing some files I would like to update a Label
on the Form
with the current status of thread2
's work.
我怎么能这样做?
推荐答案
有关.NET 2.0中,这里有code不错有点我写的不正是你想要什么,而且适用于任何财产上的控制
:
For .NET 2.0, here's a nice bit of code I wrote that does exactly what you want, and works for any property on a Control
:
private delegate void SetControlPropertyThreadSafeDelegate(
Control control,
string propertyName,
object propertyValue);
public static void SetControlPropertyThreadSafe(
Control control,
string propertyName,
object propertyValue)
{
if (control.InvokeRequired)
{
control.Invoke(new SetControlPropertyThreadSafeDelegate
(SetControlPropertyThreadSafe),
new object[] { control, propertyName, propertyValue });
}
else
{
control.GetType().InvokeMember(
propertyName,
BindingFlags.SetProperty,
null,
control,
new object[] { propertyValue });
}
}
这样称呼它:
Call it like this:
// thread-safe equivalent of
// myLabel.Text = status;
SetControlPropertyThreadSafe(myLabel, "Text", status);
如果您使用的是.NET 3.0或以上,你可以把上面的方法为控制
类,然后将简化呼叫的扩展方法:
If you're using .NET 3.0 or above, you could rewrite the above method as an extension method of the Control
class, which would then simplify the call to:
myLabel.SetPropertyThreadSafe("Text", status);
更新05/10/2010:
有关.NET 3.0,你应该使用code:
For .NET 3.0 you should use this code:
private delegate void SetPropertyThreadSafeDelegate<TResult>(
Control @this,
Expression<Func<TResult>> property,
TResult value);
public static void SetPropertyThreadSafe<TResult>(
this Control @this,
Expression<Func<TResult>> property,
TResult value)
{
var propertyInfo = (property.Body as MemberExpression).Member
as PropertyInfo;
if (propertyInfo == null ||
!@this.GetType().IsSubclassOf(propertyInfo.ReflectedType) ||
@this.GetType().GetProperty(
propertyInfo.Name,
propertyInfo.PropertyType) == null)
{
throw new ArgumentException("The lambda expression 'property' must reference a valid property on this Control.");
}
if (@this.InvokeRequired)
{
@this.Invoke(new SetPropertyThreadSafeDelegate<TResult>
(SetPropertyThreadSafe),
new object[] { @this, property, value });
}
else
{
@this.GetType().InvokeMember(
propertyInfo.Name,
BindingFlags.SetProperty,
null,
@this,
new object[] { value });
}
}
它使用LINQ和lambda EX pressions允许更清洁,更简单和更安全的语法:
which uses LINQ and lambda expressions to allow much cleaner, simpler and safer syntax:
myLabel.SetPropertyThreadSafe(() => myLabel.Text, status); // status has to be a string or this will fail to compile
不仅是现在在编译时检查的属性名称,属性的类型是一样,所以这是不可能的(例如)分配一个字符串值布尔属性,从而导致运行时异常。
Not only is the property name now checked at compile time, the property's type is as well, so it's impossible to (for example) assign a string value to a boolean property, and hence cause a runtime exception.
不幸的是,这并不不要做傻事阻止任何人如在传递另一个控制
的属性和值,所以下面将愉快地编译:
Unfortunately this doesn't stop anyone from doing stupid things such as passing in another Control
's property and value, so the following will happily compile:
myLabel.SetPropertyThreadSafe(() => aForm.ShowIcon, false);
于是我加入了运行时检查,以确保传入的属性不会真正属于控制
,该方法的调用上。并不完美,但依然有很多比.NET 2.0的版本更好。
Hence I added the runtime checks to ensure that the passed-in property does actually belong to the Control
that the method's being called on. Not perfect, but still a lot better than the .NET 2.0 version.
如果任何人有关于如何改进这个$ C $下编译时安全的任何进一步的建议,请发表评论!
If anyone has any further suggestions on how to improve this code for compile-time safety, please comment!
这篇关于如何更新从C#中的另一个线程的GUI?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!