Windows Develop Bookmark and Share   
 index > Windows Forms Designer > Custom control displays differently in TabPage
 

Custom control displays differently in TabPage

I'm having a problem with the TabPage control and how it renders child controls. My first question is, is this the proper forum?

OK, here's the issue: I have custom control which consists of a GroupBox and a CheckBox (the CheckBox's parent/container is the GroupBox). (http://www.codeproject.com/KB/miscctrl/CheckGBAndRadioGB.aspx) The CheckBox is directly over the title of the GroupBox, giving the illusion that it is a CheckBox GroupBox. When the control is in any other container (WinForm, Panel, other GroupBox, etc...) it draws correctly (the text of the CheckBox is overdrawn on top of the text of the GroupBox), but when the control is within a TabPage, both the text of the GroupBox and the text of the CheckBox is displayed. Since the text isn't drawn at the same location the text is unreadable.

If that description was unclear, here's what I'm assuming is going on when the control is drawn (when not in a TabPage):

GroupBox's border is drawn
GroupBox's caption is drawn
Bounds rect of CheckBox is erased (erasing text of the GroupBox)
CheckBox's checkbox is drawn
CheckBox's caption is drawn


But when drawn in a TabPage:
GroupBox's border is drawn
GroupBox's caption is drawn
>>>Bounds rect of CheckBox IS NOT erased <<<
CheckBox's checkbox is drawn
CheckBox's caption is drawn

...and at this point both the text of the GroupBox and the text of the CheckBox (which aren't in the same x,y location) appear to the user.

Any suggestions? For runtime I've overridden the GroupBox's Text property to replace the text with spaces:

public override string Text
{
get
{
if(this.Site != null && this.Site.DesignMode == true)
{
// Design-time mode
// Can't call base.Text = " "; here because VisualStudio crashes
return this.m_checkBox.Text;
}
else
{
// Run-time
Size textSize = TextRenderer.MeasureText(this.m_checkBox.Text, this.m_checkBox.Font);
int nTargetWidth = CHECKBOX_TEXT_GAP + textSize.Width;

// Set starting string to seven spaces. This is roughly the
StringBuilder sb = new StringBuilder(" ");
for(int i = 0; i < this.m_checkBox.Text.Length; i++)
{
sb.Append(' ');
}

do
{
sb.Append(' ');
textSize = TextRenderer.MeasureText(sb.ToString(), this.m_checkBox.Font);
} while(textSize.Width < nTargetWidth);

return sb.ToString(); // Set the text of the GroupBox to spaces so the text is 'blank' and the line doesn't appear through the text.
}
}
.
.
.

...which at least displays correctly at run-time, but at design-time in the WinForms designer there is still the issue of the text appearing. Any suggestions? Oh, and BTW, this is under WinXP, and happens with Visual Studio 2005 using .NET 2.0, and with Visual Studio 2008 using .NET 3.5.

Thanks,


Jeff

Jeff99999  Sunday, August 09, 2009 6:37 PM
Hi webJose,

Thanks for the suggestion, but I had already tried that approach and it doesn't work. If you follow steps 1-6 that you list, and then add the [Designer(...)] attribute like the MSDN article describes, one is then not able to add controls to the custom control - instead, it appears that the added controls are added, but it appears behind the custom control.


With my control, there are two approaches I could have taken:

A) Create a UserControl, and add a GroupBox and a CheckBox to the control (like I've outlined here)
B) Create a UserControl, add a CheckBox control, and override the UserControl's OnPaint method and draw the border myself.

I opted to go with option A because I wanted the appearance of my GroupBox-looking control to look just like a regular GroupBox on any particular system, and since XP, Vista, and Windows Server 2003 all draw GroupBox controls differently (not to mention if the user has tweaked the system UI appearance), I opted to add a GroupBox control to my UserControl, leaving it up to the OS to draw.

Oh, I should also point out that happens with both VS2005 Pro and VS2008 Pro, under XP. If you get different results, please let me know.


Jeff

  • Marked As Answer byJeff99999 Monday, September 14, 2009 3:55 AM
  •  
Jeff99999  Saturday, September 05, 2009 6:01 PM
As pointed out by webJose you are seeing this because CheckBox is becoming Transparent with the GroupBox. There's not a lot you can do about that if you want the controls to paint correctly, other than set the checkbox BackColor to not Transparent. You will see the same effect if you add your control toa Panel (or other container) with theBackColor set to Transparent.

Your best option is option B and use the System.Windows.Forms.GroupBoxRender to draw the GroupBox as the System would draw it. Just remember to clip the area behind the checkbox before you draw the groupbox border.

Personally, I would draw the checkbox too, but that requires a fair amount of mouse and keyboard monitoring in order to get the right state so it's much simpler for you to add a checkbox to the usercontrol.
Mick Doherty
http://dotnetrix.co.uk
  • Marked As Answer byJeff99999 Monday, September 14, 2009 3:55 AM
  •  
Mick Doherty  Sunday, September 06, 2009 5:28 PM
Hi Jeff99999,

In order to understand your issue correctly, could you please post the screen shot of that. You can upload it to http://skydrive.live.com/.

Sincerely,
Kira Qian
Please mark the replies as answers if they help and unmark if they don't.
Kira Qian  Tuesday, August 11, 2009 3:45 AM
OK, it's at http://cid-67ed036ea9579a99.skydrive.live.com/self.aspx/.Public/GroupBoxBug.jpg

You can repro it yourself by

A) Downloading the control (URL is in previous message)

or

B) Perform the following steps:
1. Create a WinForm
2. Add a Tab control
3. Add a GroupBox to the Tab control
4. Add a CheckBox to the GroupBox
5. Move the CheckBox so it is over the text of the Tab control.


Jeff
Jeff99999  Tuesday, August 11, 2009 1:50 PM
Hi Jeff99999,

Thank you for your screen shot, that really help me to know the issue. I have reproduce the problem on my computer too. I am sure it is because the text of the groupbox header is covered by the text of the checkbox. You'd better either not use text for groupbox header or text for checkbox. That will let you see the text clearly.

Am I misunderstood your requirement? If so, please feel free to tell me.

Sincerely,
Kira Qian
Please mark the replies as answers if they help and unmark if they don't.
Kira Qian  Wednesday, August 12, 2009 2:03 AM
Yea.... I don't think you are getting the issue. I've created a custom control - a groupbox that can be checked so the checkbox __is supposed__ to be over the text of the group box. If you read the article at http://www.codeproject.com/KB/miscctrl/CheckGBAndRadioGB.aspx it should be apparent what the intent is.

Well, as another example of what's going on, take a look at: http://cid-67ed036ea9579a99.skydrive.live.com/self.aspx/.Public/GroupBox2.jpg

The first CheckGroupBox is within a tab page. It has the text, "checkGroupBox1" but since the check box isn't erasing the background as it is drawn, both the text of the groupbox and the text of the checkbox are displayed, making the text unreadable.

The second CheckGroupBox (whose parent is the WinForm) and the third CheckGroupBox (whose parent is a Panel) both display correctly.

It looks like what's going on when the control is not in a tab page is:

GroupBox's border is drawn
GroupBox's caption is drawn
Bounds rect of CheckBox is erased (erasing text of the GroupBox)
CheckBox's checkbox is drawn
CheckBox's caption is drawn


...but when the control is in a TabPage:
GroupBox's border is drawn
GroupBox's caption is drawn
>>>Bounds rect of CheckBox IS NOT erased <<<
CheckBox's checkbox is drawn
CheckBox's caption is drawn




That's just a guess though...

Thanks,

Jeff

Jeff99999  Wednesday, August 12, 2009 5:26 AM
Hi Jeff99999,

Sorry may be my expression confuse you. I did have tested these two situation. One is on a form and another is on Tabpage. And see the same look as you described. When put groupbox with checkbox on a form looks pretty but on a tabpage look dirty. Checkbox rectangle doesn't cover the groupbox caption. Thank you for the valuable feedback. I suggest you'd better submit it to the Microsoft Connect, so that you can get notification email from Microsoft to track solving process of the issue.

In order to temporarily make it work, you'd better delect the text of the Groupbox, so the checkbox text can be clearly seen.

If I misunderstood you, please feel free to tell me.

Sincerely,
Kira Qian
Please mark the replies as answers if they help and unmark if they don't.
Kira Qian  Wednesday, August 12, 2009 6:33 AM
> In order to temporarily make it work, you'd better delect the text of the Groupbox, so the checkbox text can be clearly seen.

Well, therein lies the problem For the designer I just want to expose the Text property of my control. This makes sense to the user because every control out there, including a standard GroupBox has a property called Text to set the text of the control. So in my CheckGroupBox code I have:

public override string Text
{
get
{
if(this.Site != null && this.Site.DesignMode == true)
{
// Design-time mode
// Can't call base.Text = " "; here because VisualStudio crashes
return this.m_checkBox.Text;
}
else
{
// Run-time
Size textSize = TextRenderer.MeasureText(this.m_checkBox.Text, this.m_checkBox.Font);
int nTargetWidth = CHECKBOX_TEXT_GAP + textSize.Width;

// Set starting string to seven spaces. This is roughly the
StringBuilder sb = new StringBuilder(" ");
for(int i = 0; i < this.m_checkBox.Text.Length; i++)
{
sb.Append(' ');
}

do
{
sb.Append(' ');
textSize = TextRenderer.MeasureText(sb.ToString(), this.m_checkBox.Font);
} while(textSize.Width < nTargetWidth);

return sb.ToString(); // Set the text of the GroupBox to spaces so the text is 'blank' and the line doesn't appear through the text.
}
}
set
{
this.m_checkBox.Text = value;
}
}


At runtime, this seems to work. At design time however, I can't override the setting of the base GroupBox's text:

get
{
if(this.Site != null && this.Site.DesignMode == true)
{
// Design-time mode

base.Text = " "; // <<<<

return this.m_checkBox.Text;
}


...because VisualStudio crashes. How do I delete the text of base.Text (or set the text to spaces) without VisualStudio crashing? Or is there another approach you recommend?

Thanks,

Jeff




Jeff99999  Wednesday, August 12, 2009 4:28 PM
Hi Jeff99999,

My suggestion is to use a usercontrol instead of inherite from Groupbox. Put a Groupbox into the usercontrol panel and mark its Dock property to Fill, delete its Text. Create a CheckBoxText property like this.
public partial class CheckGroupBox : UserControl
{
public CheckGroupBox()
{
InitializeComponent();
}

public string CheckBoxText
{
get { return this.checkBox1.Text; }
set { this.checkBox1.Text = value; }
}
}
So that user can change checkbox's text without error. Hope this helps you.

If you have any question, please feel free to tell me.

Sincerely,
Kira Qian
Please mark the replies as answers if they help and unmark if they don't.
Kira Qian  Thursday, August 13, 2009 2:06 AM
That approach opens a Pandora’s Box and has negative side effects. If you:
1. Create a new UserControl
2. Add a GroupBox to the UserControl and set its Doc property to Fill
3. Add a CheckBox to the GroupBox
4. Save the control
5. Open a WinForm in a designer
6. Add the new UserControl that was created to the WinForm (doesn't matter if it is in form on in a tab page for this issue)

...now add a button to the user control. It will look correct, but if you move the user control around you will observe that the button doesn't move with the user control.

If you open the form's Designer.cs file you will see that the button was added to the WinForm, not the UserControl. I've seen this before with a different control I was working on and it has to do with the GroupBox/UserControl combo not behaving like a proper container.

Not only does this approach have negative side effects (if I remember correctly, when the app runs the button doesn't receive mouse clicks, probably due to the z-ordering) but this break my original CheckGroupBox control's means to enable/disable all child controls within the GroupBox.

Any other suggestions?


Jeff



  • Edited byJeff99999 Thursday, August 13, 2009 3:19 PM
  •  
Jeff99999  Thursday, August 13, 2009 5:53 AM
Jeff:

Your original problem comes from the fact that a tab control create tab pages whose background color is set to Transparent. This has the effect of removing the background on the controls that you drop into the tab. Because this happens, now the background of the checkbox no longer hides the groupbox's text.

But this is not necessarily the tabpage's fault. The control is designed poorly. If I were to create a custom control like this one, I would have taken the UserControl approach as well. Like this:

  1. Create a new UserControl and rename it.
  2. Add a GroupBox.
  3. Clear the Text property of the GroupBox and never use it.
  4. Add a CheckBox control.
  5. Clear the CheckBox's Text property.
  6. Override the UserControl's Text property to get and set the CheckBox's Text property.

This would have been at least what I would have done. To make it behave as it was a Control container, I would have followed http://support.microsoft.com/kb/813450.

Furthermore, I would have overriden the OnPaint() method of the UserControl where I would have asked the GroupBox to refresh, then I would have drawn a rectangle in the background color where the CheckBox is, and then I would have asked the CheckBox to refresh.
MCP
webJose  Friday, September 04, 2009 4:10 PM
Hi webJose,

Thanks for the suggestion, but I had already tried that approach and it doesn't work. If you follow steps 1-6 that you list, and then add the [Designer(...)] attribute like the MSDN article describes, one is then not able to add controls to the custom control - instead, it appears that the added controls are added, but it appears behind the custom control.


With my control, there are two approaches I could have taken:

A) Create a UserControl, and add a GroupBox and a CheckBox to the control (like I've outlined here)
B) Create a UserControl, add a CheckBox control, and override the UserControl's OnPaint method and draw the border myself.

I opted to go with option A because I wanted the appearance of my GroupBox-looking control to look just like a regular GroupBox on any particular system, and since XP, Vista, and Windows Server 2003 all draw GroupBox controls differently (not to mention if the user has tweaked the system UI appearance), I opted to add a GroupBox control to my UserControl, leaving it up to the OS to draw.

Oh, I should also point out that happens with both VS2005 Pro and VS2008 Pro, under XP. If you get different results, please let me know.


Jeff

  • Marked As Answer byJeff99999 Monday, September 14, 2009 3:55 AM
  •  
Jeff99999  Saturday, September 05, 2009 6:01 PM
As pointed out by webJose you are seeing this because CheckBox is becoming Transparent with the GroupBox. There's not a lot you can do about that if you want the controls to paint correctly, other than set the checkbox BackColor to not Transparent. You will see the same effect if you add your control toa Panel (or other container) with theBackColor set to Transparent.

Your best option is option B and use the System.Windows.Forms.GroupBoxRender to draw the GroupBox as the System would draw it. Just remember to clip the area behind the checkbox before you draw the groupbox border.

Personally, I would draw the checkbox too, but that requires a fair amount of mouse and keyboard monitoring in order to get the right state so it's much simpler for you to add a checkbox to the usercontrol.
Mick Doherty
http://dotnetrix.co.uk
  • Marked As Answer byJeff99999 Monday, September 14, 2009 3:55 AM
  •  
Mick Doherty  Sunday, September 06, 2009 5:28 PM
Thanks,

My next approach is to try overriding the OnPaint() method and then clip (remove) the bounds of the checkbox before the GroupBox is painted, and if that doesn't work crate a control that's derived from a user control and call GroupBoxRender() in OnPaint as you suggest.

Thanks,

Jeff
Jeff99999  Monday, September 14, 2009 3:55 AM

You can use google to search for other answers

Custom Search

More Threads

• datagridview help
• ToolBox Tab
• Little problem with the VS Editor extending the standard behavior from a Form
• Adding CheckedChanged event handler destroys my form, removing it instantly recovers my form
• redering forms onto polygons
• IResourceService
• usercontrol !
• IObjectSafety
• How to extract a form from a project
• ReportViewer designer issue (Not able to see in designer)