views:

127

answers:

2

Hello,

I am working on creating a thread safe control for my windows forms application.

I understand I can set the text on a control thread safe by using the following code:

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

Then in my form code i can call:

SetText(lblStatus, "Updating...");

My goal is to create a custom control, which inherits Label. Then inside this class, on the Text property I can just call:

lblStatus.Text = "Updating..."

Then it will automatically do the proper thread safe code.

Here is the code that I have in my class:

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

Now, when I attempt to add this control to my form, it crashes VS 2008. I was thinking that maybe it had to do with setting the initial text property when you add it to the form, but not sure.

Any thoughts on what I might be doing wrong or what I might be missing?

If something is not clear, please ask.

Thanks!

+2  A: 

Try a

return base.Text;

or you will run into a endless loop (when you add the Label to your Form the Text-property is queried - and the endless loop makes VS crash). Same for your setter.

tanascius
+1  A: 

Because of C# 3.0's anonymous methods, you don't need separate set and get methods. The simplest way to do what you're looking for is like this:

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

Note that I'm using BeginInvoke so that the calling thread will not wait for the invoke to complete; you might want to change it to Invoke.

EDIT:

The problem with your code is that your set and get methods are calling your overridden Text property again, creating an infinte loop that results in a stack overlow (the exception, not the website). You need to write base.Text to call the base class' implementation of the Text property.

SLaks
Yes, the point is to use base.Text ... after that he can refactor the code to work without delegates.
tanascius
This is what it was. Thank you for the info.
Jason Heine