Problem overriding Font property of TextBox

  • Thread starter Thread starter Olaf Krumnow
  • Start date Start date
O

Olaf Krumnow

I'm trying to override the Font property of some controls.
For a Label this works as expected, but the TextBox ignores
the value returned from the subclass. This small example
shows this effect. I set the Font ot the form to 6pt Sans Serif
so normally all controls would be using this font.
Now I have two classes, one inheriting from Label and one from
TextBox. Both override the Font property and return a 16pt Comic
font.

When running, the Label uses the Comic font but the TextBox
doesn't. Why? And how can I get what I want?

Regards Olaf

-- source --

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace WindowsApplication12
{
public class Form1 : System.Windows.Forms.Form
{
public Form1()
{
this.ClientSize = new System.Drawing.Size(292, 273);
this.Font = new System.Drawing.Font("Microsoft Sans Serif", 6F);

TB tb = new TB();
tb.Text = "Hello";
this.Controls.Add(tb);
LB lb = new LB();
lb.Text = "Hello";
lb.SetBounds(0, 20, 100, 30);
this.Controls.Add(lb);
}

[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}

internal class TB: System.Windows.Forms.TextBox
{
public override Font Font
{
get { return new Font("Comic Sans MS", 16); }
}
}

internal class LB: System.Windows.Forms.Label
{
public override Font Font
{
get { return new Font("Comic Sans MS", 16); }
}
}
}
 
Both override the Font property and return a 16pt Comic

By overriding the Font property you are saying whenever you call my object and ask for the Font property return this value, so a caller who call who queries this property will get your font object but you are not setting a Font on the control. Note how the accessor on control has both a get and a set method, the set method does a lot of work to implement changing the font on a control - a decompiler like Lutz Roeder's Reflector makes this easier to read than ILDASM. So you what you want to do is set the Font property in your derived control's constructor - don't override the Font accessor's get method - that will return the Font you set in the constructor. If you don't want a developer to be a change that font in the designer your probably better off using attributes to hide the property.

Ian Cooper
www.dnug.org.uk
 
By overriding the Font property you are
saying whenever you call my object and
ask for the Font property return this
value, so a caller who call who queries
this property will get your font object
but you are not setting a Font on the control.

But this doesn't explain why the label works OK
and the TextBox doesn't. BTW: I can't follow your
argumentation. Each control should use the Font
property for examining the active font (and most
controls do so). Otherwise there would be very
little sense in making the property overridable.

Regards
Olaf
 
Olaf - Ian is correct. Set the Font property in your derived control's
ctor - that is the way to make it work - end of story.

I have no idea why Label "works", but I wouldn't count on that behavior...

HTH,
TJ
 
So, "End of Story", Tom? A bit too simple, I think...

Well, the example I provided is simplified, of course, to focus on the
problem
I was asking for. I didn't ask "how can I set the font of a control?"
I did ask: why is the TextBox (or the TreeView or the ComboBox) not
displaying
the font that the (overridden) Font property (in a derived class) returns,
like the Label does
(or the button or the checkbox or the radio button, didn't try all
controls).

To make the example a bit more "real life", assume that the Font property in
my
classes did not simply return a fixed font, but instead varies the base
font, ie.
the font a call to base.Font returns. This font can be a font directly set
with
control.Font, or it can be the font of the control's parent or the control's
parent parent (up to the root control, for example a form).

Basically my programs set the font of the form the desktop font of the
system it is running on. To have a consistent look, no controls sets an own
font but instead vary the base font, ie. make it a bit larger and bold for
a headline, make it italic to highlight a control etc. etc.
A Label shows this varied Font, TextBox not.

Obviously I can't set the Font property, like Ian and you suggested,
as this "shadows" the font of the parent and breaks my concept.
Setting all control's fonts at startup (in ctor) won't notice changes at
runtime,
for example in an Options dialog, that allows the user to select the
base font to use.

So, my question is still: why does the TextBox behave this way?
Is it a bug or is it "by design"? How can I work around the problem?


Regards
Olaf
 
why is the TextBox (or the TreeView or the ComboBox) not
displaying the font that the (overridden) Font property (in a derived class) returns,
like the Label does (or the button or the checkbox or the radio button, didn't try all
controls).
Because you are not overriding the Font property. You have only overrrided the get accessor on the Font property, but not the set. It is a read-write property. So you have no synchronization between what is set via a call to set_Font and what is retrieved by a call to get_Font. You are relying on set_Font doing no work, and on the control being implemented so that it when it calls WM_SETFONT it passes a font retrieved by calling its get_Font accessor. Yet it is quite likely that a valid implementation will call WM_SETFONT in response to the set_Font call. The contract on a read-write accessor is surely explicity set using set_ and retrieve using get_. You are not meeting all of that contract - its both or nothing.
[Point a decompiler like reflector at the get_Font and set_Font methods (ILDASM will do if you can decipher IL). There is a lot of work going on there. Some of it supports ambient properties, some of it initiliazes the control's internal state. Are you sure you don't want any of that?]
I understand that it works for you on some controls - but you are relying on the implementation details of that control,and you are relying on them not changing. That is never a good plan.
The reason font is virtual is so that you can put your own handling in place for custom controls - but then you are responsible for painting the control on custom controls (as opposed to inherited controls).
If you do not want the user to edit the Font property in your derived class set its property to [Browsable(false)]. If you do not want the user to access SetFont from code then yourTextBox needs to go in a User Control so that you can control the programming interface (i.e hand out only Size and Style properties not family) to the control because you fail the Lykov substitution test.
Ian Cooper
wwww.dnug.org.uk
 
Back
Top