I have a question about UI in visual studio, in C#. I want to make my groupbox custom to look like this:
and then, I also want it to expend depends on the user's screen resolution, so the size of the group box isn't fixed, and I need it to be for example 80% of the screen.
So my question is actually two question:
- make a groupbox costum
- make it 80% (for example) wide of the screen.
EDIT: thanks to this answer: How to make group box text alignment center in win forms?
I managed to do what I wanted with the colors, now I am just missing the round corners. any ideas?
As an option you can create a custom control deriving from GroupBox
:
- You need to calculate a round rectangle shape. To do so, as an option you can use
AddArc
method and add arcs to four corners of a rectangle in a path.
- To draw header background with hatch style, you can use a
HatchBrush
. So add a property for title hatch style. This way you can use different HatchStyle
values for title back-ground.
- To have a different title color and title font, add some properties to control.
- In a more complete implementation, you should implement properties in a way which setting a new value to property cause repainting the control by calling
this.Invalidate()
.
- To prevent flicker while resizing turn on double buffering by setting
DoubleBuffered
to true
in constructor.
- To have transparent background in corners, use
GroupBoxRenderer.DrawParentBackground
.
Screenshot
Code
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class RoundPanel : GroupBox
{
public RoundPanel()
{
this.DoubleBuffered = true;
this.TitleBackColor = Color.SteelBlue;
this.TitleForeColor = Color.White;
this.TitleFont = new Font(this.Font.FontFamily, Font.Size + 8, FontStyle.Bold);
this.BackColor = Color.Transparent;
this.Radious = 25;
this.TitleHatchStyle = HatchStyle.Percent60;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
GroupBoxRenderer.DrawParentBackground(e.Graphics, this.ClientRectangle, this);
var rect = ClientRectangle;
using (var path = GetRoundRectagle(this.ClientRectangle, Radious))
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
rect = new Rectangle(0, 0,
rect.Width, TitleFont.Height + Padding.Bottom + Padding.Top);
if(this.BackColor!= Color.Transparent)
using (var brush = new SolidBrush(BackColor))
e.Graphics.FillPath(brush, path);
var clip = e.Graphics.ClipBounds;
e.Graphics.SetClip(rect);
using (var brush = new HatchBrush(TitleHatchStyle,
TitleBackColor, ControlPaint.Light(TitleBackColor)))
e.Graphics.FillPath(brush, path);
using (var pen = new Pen(TitleBackColor, 1))
e.Graphics.DrawPath(pen, path);
TextRenderer.DrawText(e.Graphics, Text, TitleFont, rect, TitleForeColor);
e.Graphics.SetClip(clip);
using (var pen = new Pen(TitleBackColor, 1))
e.Graphics.DrawPath(pen, path);
}
}
public Color TitleBackColor { get; set; }
public HatchStyle TitleHatchStyle { get; set; }
public Font TitleFont { get; set; }
public Color TitleForeColor { get; set; }
public int Radious { get; set; }
private GraphicsPath GetRoundRectagle(Rectangle b, int r)
{
GraphicsPath path = new GraphicsPath();
path.AddArc(b.X, b.Y, r, r, 180, 90);
path.AddArc(b.X + b.Width - r - 1, b.Y, r, r, 270, 90);
path.AddArc(b.X + b.Width - r - 1, b.Y + b.Height - r - 1, r, r, 0, 90);
path.AddArc(b.X, b.Y + b.Height - r - 1, r, r, 90, 90);
path.CloseAllFigures();
return path;
}
}
One option is to develop your own custom control derived from GroupBox
and override the OnPaint()
method to do your drawing.
public class CustomGroupBox : GroupBox
{
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.FillRectangle(Brushes.Azure, this.ClientRectangle);
//base.OnPaint(e);
}
}
The new control will appear in the Toolbox after a build automatically.
To draw this object the DrawPath
method can be used to draw the outer rectangle and the FillPath
method can be used to fill the upper bar.
https://msdn.microsoft.com/en-us/library/system.drawing.graphics.drawpath(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.drawing.graphics.fillpath(v=vs.110).aspx
Elastic design can be done with TableLayoutPanel
.
For WPF:
You can create a Style
to make your GroupBox
appear in a different way.
Maybe this can help you there: Styling a GroupBox
For Windows Forms:
To change the Layout you can have a look at this:
https://stackoverflow.com/a/31828317/4610605
To resize the GroupBox
you can use this:
System.Windows.SystemParameters.PrimaryScreenWidth
System.Windows.SystemParameters.PrimaryScreenHeight
GroupBox gb = new GroupBox();
gb.Width = (System.Windows.SystemParameters.PrimaryScreenWidth * 0.8) //Get your 80% ScreenWidth here.
This is a pure XAML solution, no custom control or code. It just uses the standard WPF style/template technique. Generally it is preferred to use styles/templates over custom controls.
GroupBox header can be different size so I added the option of changing the header text with the "Tag" property (currently set to 18).
Demo of usage:
<GroupBox Style="{StaticResource GBStyled}" Tag="18"
Header="Hello" Height="150" Width="180">
<TextBlock TextWrapping="Wrap">Text is different size to Header</TextBlock>
</GroupBox>
Style definition:
<Style x:Key="GBStyled" TargetType="GroupBox">
<!-- These 2 setters make the GroupBox less blurry -->
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="UseLayoutRounding" Value="True"/>
<!-- Default Background colour -->
<Setter Property="Background" Value="White"/>
<!-- Template of GroupBox -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupBox">
<ControlTemplate.Resources>
<!-- Custom hatched brush -->
<VisualBrush x:Key="MyVisualBrush" TileMode="Tile" Viewport="0,0,5,5" ViewportUnits="Absolute" Viewbox="0,0,15,15" ViewboxUnits="Absolute">
<VisualBrush.Visual>
<Grid Background="{StaticResource DarkBlueBrush}">
<Path Data="M 0 15 L 15 0" Stroke="White" />
<Path Data="M 0 0 L 15 15" Stroke="White" />
</Grid>
</VisualBrush.Visual>
</VisualBrush>
</ControlTemplate.Resources>
<Grid>
<Grid.Resources>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="0" CornerRadius="5,5,0,0" BorderThickness="1" BorderBrush="{StaticResource DarkBlueBrush}" Background="{StaticResource MyVisualBrush}">
<!-- FontSize of the header is changed via the Templates "Tag" property -->
<Label Foreground="White" FontSize="{Binding RelativeSource={RelativeSource AncestorType=GroupBox}, Path=Tag}" HorizontalAlignment="Center" FontWeight="Bold">
<!-- DropShadow makes the label standout from the background -->
<Label.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="3" />
</Label.Effect>
<ContentPresenter Margin="0" ContentSource="Header" RecognizesAccessKey="True"/>
</Label>
</Border>
<Border Grid.Row="1" CornerRadius="0,0,5,5" BorderThickness="1,0,1,1" BorderBrush="{StaticResource DarkBlueBrush}" Background="{TemplateBinding Background}">
<ContentPresenter Margin="4" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>