Introduction
At times, I find myself building extra functionality around standard .NET controls, but adding that functionality litters my application code with what are essentially bookkeeping functions with which I shouldn't have to concern myself. Additionally, I find myself repeatedly adding the same functionality into different applications. So I eventually decided to explore ways of adding functionality to the controls themselves, and sharing them between applications.
Background
I found two basic ways to accomplish what I want to do. The first is by extending the .NET Label
control, and the second is to build my own control that inherits from the .NET Label
control. Each method has its strengths, so let's look at them one at a time.
I wrote my code in C# .NET, using Visual Studio 2010.
Using the Code
For this example, I will be adding some basic functionality to a simple control, but the principles extend much farther than this example. In this case, I'll be modifying the .NET Label
class to add the ability to fade the text out after a specified number of seconds.
Let me begin by making clear what I do NOT want to do. I do not want to create a custom or user control, nor do I want to create a brand new control from scratch, because those would not be of type Label
. Why recreate the wheel and go to the trouble of creating a new Label
control, especially when I can retain the existing Label
control and let it do all of the heavy lifting? All I want to do is layer my new functionality on top of the existing control.
The first method of accomplishing this is by adding an extension method to the Label
class. Basically, the new method is added directly onto the control's functionality whenever the appropriate using
statement is placed in the application code.
We start by setting up the namespace, then declaring the static
class. Note that the extension class must be static
, as must all the functions within it. The code below extends the .NET Label
class to include the ShowFadeText()
method.
namespace ControlExtensions
{
public static class LabelExtension
{
public static void ShowFadeText(this Label lbl, String text, int seconds)
{
lbl.Text = text;
lbl.Visible = true;
Timer tmr = new Timer();
tmr.Interval = seconds * 1000;
tmr.Tick += new EventHandler(tmr_Tick);
tmr.Tag = lbl; tmr.Start();
}
static void tmr_Tick(object sender, EventArgs e)
{
Timer tmr = ((Timer)sender);
Label lbl = ((Label)tmr.Tag); lbl.Text = "";
tmr.Stop();
}
}
}
Notice the first parameter of the static ShowFadeText()
method... it indicates what class the extension method applies to. It also allows the control to be addressed within the extension method. So we first set the text and make sure the control is visible, then we configure and kick off a timer for the number of seconds specified in the final parameter.
The timer method was a bit tricky, because it has to reference the label
control... the specific label
that invoked the extension method. We can't simply save the Label
to a private
class variable, because this is a static
class, and this wouldn't support multiple fading Labels
at the same time. To do this, we have to pass the Label
into the tmr_Tick
handler somehow, and to do that I give you the Tag
property. So, inside the ShowFadeText()
method, before we kick off the timer, we set the Tag
to the label
control.
Inside the tmr_Tick
event handler, we extract the timer control from the sender parameter, and then we extract the label
control from the tmr.Tag
. Finally, we set the Label
to an empty string
and stop the timer.
When it comes to using this extension method, the first step is to make sure the application code is referencing the namespace that contains the extension method.
using ControlExtensions;
Without that line, the extension method is not implemented and is not available. But with that line, all you need to do is drop a label
onto the form and then call the extension method as follows:
label1.ShowFadeText("This text should fade out in 3 seconds...", 3);
This method accomplishes the goal for adding this simple functionality, but it does have some limitations. For example, though we can create extension methods, we can't create extension properties or events. We also can't override existing methods, so it's not the most flexible solution... we can't CHANGE the behavior of the Label
control this way, we can only add to it.
That's why I had to create a new method to set the fade text, instead of just using the Label.Text
property... using an extension method, I can't change the Text
property, I can only add new methods.
A more robust solution is to create a new control that inherits from the Label
control, and place the new functionality there. The code below is the entire code needed to implement the custom Label
control.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MyLib
{
namespace Controls
{
public class MyLabel : Label
{
private int? timeLimit; private Timer tmr;
public int? TimeLimit
{
get { return timeLimit; }
set
{
timeLimit = value;
if (timeLimit != null)
tmr.Interval = (int)TimeLimit * 1000;
}
}
public MyLabel()
{
TimeLimit = null;
tmr = new Timer();
tmr.Tick += new EventHandler(tmr_Tick);
tmr.Tag = this;
}
public override String Text
{
get { return base.Text; }
set
{
base.Text = value;
if (TimeLimit != null && TimeLimit > 0)
tmr.Start();
}
}
void tmr_Tick(object sender, EventArgs e)
{
Timer tmr = ((Timer)sender);
this.Text = "";
tmr.Stop();
}
}
}
}
Unlike with the first example, in this case I didn't create a custom method to display the text and fade it out. In this case, the code will fire the timer IF the TimeLimit
property has a value greater than 0
when the MyLabel.Text
property is set.
The code adds three public
members:
- A property named
TimeLimit
that stores a nullable integer representing the number of seconds for the label to display before it disappears.
- A
public
constructor for MyLabel
control.
- A
public
property named Text
which overrides the base Label Text
property.
When the text is set in the application code, the override property fires the timer, which is set for the number of seconds provided in the TimeLimit
property. If the TimeLimit
property is null
or 0
, then it doesn't fade. Using the new functionality looks like this:
myLabel1.TimeLimit = 5;
myLabel1.Text = "This label will fade in 5 seconds.";
This is a better solution all the way around. The MyLabel
control can be placed into the ToolBox
and dropped onto a form, or it can be invoked programmatically just like a Label
. And as you saw with the Text
property, we can override existing methods and properties, as well as add methods, properties, and events. The new properties can be referenced via the properties window in the Form Designer, as can the events.
One possible enhancement to this class, for example, would be to add a new event to it... name it the FadeoutComplete
event, which fires when the text disappears... the tmr_Tick
event after the text is cleared. In this way, the user is notified when the text fade is finished.
Points of Interest
I set out looking for one way to accomplish my goal, but ended up with two... life is funny like that. The extension method solution works well for a small change to the control, one that can be implemented by adding methods. Creating a new Label
type that inherits from the .NET Label
control, however, allows for much more versatility in creating greatly enhanced controls.
History
- 07-28-2014 - Article originally posted
- 07-28-2014 - Added source code and demo program for download