|
Creating inherited .NET components in C# • Functionality
Now, when all preparations are done, we can proceed to most creative part - creation of new functionality of our button. First, let's completely think it. First, we need to implement a method, that will return a string for caption, depending on current DialogResult property value. Intuition suggest, that it will be needed in multiple places, so we need to create a method for code reuse. Second, it would be nice to put the ability to choose character case of our autotext. It seems, that it's all. The rest, as usual, will leak up during the implementation. Let's begin.
Inside our DialogButton class create public method GetText. Because of ability of any variable to return its value in format of string, code comes out very simple. Most part of it is a code, which switches case of characters.
public class DialogButton : Button
{
public virtual string GetText()
{
string S = DialogResult.ToString();
switch (TextCharCase)
{
case CharCase.LowerCase:
S = S.ToLower();
break;
case CharCase.UpperCase:
S = S.ToUpper();
break;
}
return S;
}
...
|
To be on the safe side, make method GetText virtual, to be able to easily change the algorithm in the future with override of this metod in descendant component.
Now we need to create a property, that will control character register. It's a multistage activity. First of all, we need to declare an enumerable type for property, that will contain three choises - default, upper case and lower case. Declare new public CharCase type inside the class, and place every value on separate string (believe me, it will be clear, why we did it this way):
public enum CharCase
{
Default,
LowerCase,
UpperCase
}
|
Now, to store a property value, create private variable textCharCase with type, that we've just declared:
private CharCase textCharCase = CharCase.Default;
|
Then, create a public property TextCharCase with corresponding access methods. By the way, in method set we are using our GetText method for the first time.
public CharCase TextCharCase
{
get { return textCharCase; }
set
{
textCharCase = value;
Text = GetText();
}
}
|
To avoid property serialization in case, when it's value matches CharCase.Default, set the default value in attribute DefaultValue. To make a screen tip visible when our property is selected in Property window of Visual Studio environment, enter tip text in Description attribute:
[DefaultValue(typeof(DialogButton.CharCase), "Default"),
Description("Character case of Text property's automatical values")]
public CharCase TextCharCase
...
|
We've finished with property, but our component does not work the way we need it. To make everything be done perfectly, we need to set default value of the text on the button. Best place for it is the constructor. By the way, it's a second place, where we use GetText method, so, our intuition works well:
public DialogButton()
{
Text = GetText();
}
|
But it's not enough to set default value, it's needed to change button's text on DialogResult value change. Unfortunately, we have no such a event, so we need to override the property and to call our GetText for the third time, to be sure we are far-sighted:
public override DialogResult DialogResult
{
get { return base.DialogResult; }
set
{
base.DialogResult = value;
Text = GetText();
}
}
|
It seems, that it's all... But wait, what we need to do with original Text property inherited from Button class? We change text on the button automatically, and presence of the property,that allows to set it manually is illogical and unwanted. We need to take it away. Class, that's responsible for components list is ControlDesigner, which we are using. First of all, let's make our new internal inherited designer class for our component specially, inherit virtual method PostFilterProperties there and easily remove Text
internal class DialogButtonDesigner : ControlDesigner
{
protected override void PostFilterProperties(
System.Collections.IDictionary properties)
{
properties.Remove("Text");
base.PostFilterProperties(properties);
}
}
|
The last thing, is to link our designer with our component. It should be made via Designer attribute:
[Designer(typeof(DialogButtonDesigner))]
public class DialogButton : Button
{
...
|
To compile and run, we need to add SystemDesign build to References of our project and using System.Windows.Forms.Design; in DialogButton.cs file.
In hope we press F5 key, to run our project with full-function version of the button and... get compilation error. Visual Studio has created our button's Text property initialization string in Form1.Designer.cs, and we have deleted this property. So, let's go to the place, that's pointed by compiler, and remove the problem string. With trepidation we are pressing F5 one more time, and are happy, that the test application with our button is started at last, and works the way we expect it to do.
We have ended with functionality. The most creative part is passed, but do not feel upset and don't think, that only routine is ahead. There's a most sweet stage on our way - to give a polish to our component. What exactly we'll do, and how we'll made it, we'll discover in the last step
|