代码之家  ›  专栏  ›  技术社区  ›  CodeLikeBeaker

线程安全控制-崩溃vs 2008

  •  0
  • CodeLikeBeaker  · 技术社区  · 16 年前

    我正在为我的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...");
    

    我的目标是创建一个继承标签的自定义控件。然后在这个类中,在文本属性上,我可以调用:

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

    现在,当我试图将此控件添加到表单中时,它与2008年相比崩溃了。我在想,当您将初始文本属性添加到表单时,它可能与设置初始文本属性有关,但不确定。

    有没有想过我可能做错了什么或者我可能错过了什么?

    如果有什么不清楚,请问。

    谢谢!

    2 回复  |  直到 16 年前
        1
  •  1
  •   SLaks    16 年前

    由于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 属性,再次创建导致堆栈覆盖的内嵌循环(异常,而不是网站)。你需要写 base.Text 调用基类的实现 文本 财产。

        2
  •  2
  •   tanascius    16 年前

    试一试

    return base.Text;
    

    或者你会遇到一个无止境的循环(当你将标签添加到你的表单中时,文本属性会被查询——而无止境的循环会导致vs崩溃)。你的二传手也一样。