我正在为我的Windows窗体应用程序创建一个线程安全控件。
我知道我可以使用以下代码将控件线程上的文本设置为安全:
private delegate void SetTextD(Control control, string value);
private static void SetText(Control control, string value)
{
if(control.InvokeRequired)
{
control.Invoke(new SetTextD(SetText), new object[] {control, value});
}
else
{
control.Text = value;
}
}
然后在我的表单代码中我可以调用:
SetText(lblStatus, "Updating...");
我的目标是创建一个继承Label的自定义控件。然后在这个类中,在Text属性上我可以调用:
lblStatus.Text =“正在更新......”
然后它将自动执行正确的线程安全代码。
以下是我班上的代码:
public class ThreadSafeLabel : Label
{
private delegate string GetTextD();
private delegate void SetTextD(string value);
private string GetText()
{
if (InvokeRequired)
{
return (string)Invoke(new GetTextD(GetText));
}
return Text;
}
private void SetText(string value)
{
if(InvokeRequired)
{
Invoke(new SetTextD(SetText), new object[] {value});
}
else
{
Text = value;
}
}
public override string Text
{
get
{
return GetText();
}
set
{
SetText(value);
}
}
}
现在,当我尝试将此控件添加到我的表单时,它会崩溃VS 2008.我在想,也许它与将初始文本属性添加到表单时设置初始文本属性有关,但不确定。
关于我可能做错了什么或者我可能错过什么的任何想法?
如果不清楚,请询问。
谢谢!
答案 0 :(得分:2)
尝试
return base.Text;
或者您将遇到无限循环(当您将Label添加到表单时,将查询Text-property - 并且无限循环会导致VS崩溃)。你的二传手也一样。
答案 1 :(得分:1)
由于C#3.0的匿名方法,您不需要单独的set和get方法。做你正在寻找的最简单的方法是这样的:
public class ThreadSafeLabel : Label {
public override string Text {
get {
return InvokeRequired ? Invoke(new Func<string>(() => base.Text)) : base.Text;
}
set {
if (InvokeRequired)
BeginInvoke(new Action(() => base.Text = value));
else
base.Text = value;
}
}
请注意,我正在使用BeginInvoke
,以便调用线程不会等待调用完成;您可能希望将其更改为Invoke
。
修改强>:
你的代码的问题是你的set和get方法再次调用你被覆盖的Text
属性,创建一个infinte循环,导致堆栈过低(例外,而不是网站)。您需要编写base.Text
来调用Text
属性的基类实现。