Introduction
Recently, I had the known problem of setting the
Text
value of a ToolStripStatusLabel control from a thread other than the one that was handling it. This basically can happen when you fire an event from an independent thread method and want to display a message in the client application. The usual way to deal with this is to use the
Invoke
method of the control to delegate the operation so that it is thread-safe. Unfortunately, ToolStripStatusLabel doesn't have such a method. I searched awhile on the internet to see if someone had a solution to this problem, but I couldn't find any satisfying one.
So, I searched by myself for a solution thinking that Microsoft had surely thought about this. The solution is in the StatusStrip control that contains all of the ToolStrip controls. This class has the InvokeRequired
and Invoke
methods that are necessary to delegate the call on the right thread. I came out with two solutions, both of which work.
Extending the StatusStrip control
The first solution consists of adding a method to the StatusStrip control to safely set the Text
property of the ToolStripStatusLabel it contains. The code to achieve this is given below.
public void SafeSetText(ToolStripLabel toolStripLabel, string text)
{
if (InvokeRequired)
{
SetText setTextDel =
delegate(ToolStripLabel toolStrip, string textVal)
{
foreach (ToolStripItem item in base.Items)
{
if (item == toolStrip)
{
item.Text = textVal;
}
}
};
try
{
Invoke(setTextDel, new object[]
{
toolStripLabel, text
});
}
catch
{
}
}
else
{
foreach (ToolStripItem item in base.Items)
{
if (item == toolStripLabel)
{
item.Text = text;
}
}
}
}
The idea is quite simple. As there is no Invoke
method in ToolStripStatusLabel, I use the one of StatusStrip and find on which item I must apply the Text
change. The drawback of this technique is that I cannot directly call the Text
property of ToolStripStatusLabel and so this property remains unsafe. However, this solution works.
Extending the ToolStripStatusLabel control
The second solution satisfies me better. I override the Text
property of ToolStripStatusLabel and make it totally safe so that it is no longer possible to call the original Text
property. I think this solution is more elegant and it can be used with other ToolStrip items of a StatusStrip. The code of this solution is given below.
public override string Text
{
get
{
if ((base.Parent != null) &&
(base.Parent.InvokeRequired))
{
GetString getTextDel = delegate()
{
return base.Text;
};
string text = String.Empty;
try
{
text = (string)base.Parent.Invoke(getTextDel, null);
}
catch
{
}
return text;
}
else
{
return base.Text;
}
}
set
{
if ((base.Parent != null) &&
(base.Parent.InvokeRequired))
{
SetText setTextDel = delegate(string text)
{
base.Text = text;
};
try
{
base.Parent.Invoke(setTextDel, new object[] { value });
}
catch
{
}
}
else
base.Text = value;
}
}
As you can see in the code, this solution is more straightforward and doesn't need a separate method to set the Text
property. The trick is to get the Parent of the ToolStrip item and call the Invoke
method with the delegate to set the Text
property. The only drawback I found to this method is that you cannot use SafeToolStripStatusLabel from the designer and must modify the code generated by the designer. However, there may be a way to tell the designer to use our SafeToolStripStatusLabel when we add it to the StatusStrip control.
Demo application
In order to demonstrate both methods, I built a simple demo application that can fire one event displayed with the SafeStatusStrip control and one event displayed with the SafeToolStripLabel control. This application uses a thread that waits to send either one event or the other when a button is pressed. The event handlers display a message in the status bar using one of the two methods described previously.
Points of interest
This code can be used for any ToolStrip control that you might use in a StatusStrip container. You can use it freely in your application by building a component DLL that will contain all your safe controls.
History
- 6 July, 2007 -- Original version posted