Groupbox adjust width based on text length - c#

I have a c# app (winform) that generates Groupboxes from an xml file and based on what's in the file, populates it with Radio Buttons or CheckBoxes. Each of these groupboxes have a name, some of them are longer and they get cut off half way through.
This is how they are generated.
int nc = groupNodes.Count;
for (int i = 0; i < nc; i++)
{
node = groupNodes[i];
GroupBox box = new GroupBox();
box.AutoSize = true;
box.AutoSizeMode = AutoSizeMode.GrowAndShrink;
box.Text = node.Attributes["name"].Value;
//......
}
I tried using the following,
Size textSize = TextRenderer.MeasureText(box.Text,box.Font);
box.Width = (int)textSize.Width;
and tried the following
box.width = (int)box.text.length;
but none of this made any difference.
I also came across This thread. But since I don't use the PaintEventArgs I'm not sure how this applies to me.

Setting the groupbox width is only one of your problems.
It probably should be done like this:
groupBox.AutoSize = true;
int oWidth = groupBox1.Width;
int tWidth = (int)groupBox.CreateGraphics().
MeasureString(groupBox.Text, groupBox.Font).Width;
if (tWidth > oWidth)
{
groupBox.AutoSize = false;
groupBox.Width = tWidth;
}
Note:
This code make use of the AutoSize property. Which will make the GB wide enough to hold its content ie. the RadioButtons&CheckBoxes with their texts. Therefore these should be set before adjusting the GB sizes.
The result will have AutoSize true for some GB and false for others..
After changing the width of the GBs they will need to be repositioned unless they sit in a FlowLayoutPanel!
Their contents (The RadioButtons etc ought to still sit correctly as you placed them before). You did Add them to the GBs, right? If some don't show, post the code you create them with!
So the order is this:
Create GBs with their Text
Add contents with their Texts
Resize GBs
Reposition GBs (shouldn't be necessary with FLP)

Related

VSTO com add-in for Outlook: RichTextBox disappearing from WinForm after unrelated FormRegion displays

I am coding a VSTO com addin for Outlook. I created a form in the designer that displays as a dialog window when the user clicks a button on the ribbon. On that form is a RichTextBox that I use to display an RTF formatted message to the user. For the purposes of this question, let's call this "myRTFForm".
I also created a (completely unrelated) FormRegion that displays when a user views an email, either in the preview window or a new inspector window. Let's call this "myFormRegion".
If the user clicks the ribbon button to launch myRTFForm before viewing an email, everything is fine and the RichTextBox is visible on myRTFForm.
But, if the user clicks the ribbon button after viewing an email (thus displaying myFormRegion), myRTFForm displays, but with the RichTextBox hidden.
So for some reason, after myFormRegion is shown, the RichTextBox on (the completely unrelated) myRTFForm is getting set to hidden, and refuses to be set to visible no matter what I try. I even tried programmatically creating a new RichTextBox, and that ends up hidden as well.
If I instead use a regular text box (either through the designer or programmatically) that stays visible. So that is obviously a workaround -- but I'd really rather use the RichTextBox and its RTF formatting.
As you can see in the code below, I also did a sanity check to make sure I wasn't referencing the wrong form object -- by manually setting the RichTextBox to hidden, and sure enough, the RichTextBox comes up hidden even before viewing an email displaying myFormRegion.
One final thing -- I stepped through the code and watched the "Visible" property of the RichTextBox, and it remains true until the form's designer-generated code runs this line:
this.Controls.Add(this.groupBox1);
The weird thing is, the Visible property always turns false at this point, even when the RichTextBox actually displays properly before an email with myFormRegion is viewed.
I could not "step into" that line of code -- is there a way to do that? Perhaps with Resharper or some other tool?
If anyone has any insights into this weird behavior, I'd really appreciate it. Here is the code from the method that shows the myRTFForm dialog (the commented code shows all the things I've tried to get the RichTextBox to remain visible):
public DialogResult ShowMyDialog()
{
//_myForm.RichTextBox1.Rtf = ProcessedRTFText;
_myRichTextBox.Rtf = ProcessedRTFText;
int growIfMoreThan = 7; // Increase window height if more than this number of lines
int pixelsPerLine = 17; // Approx. number of pixels per line
int maxHeight = 800; // Max height of the window in pixels (draws a scrollbar at that point)
//int numLines = _myForm.RichTextBox1.Lines.Count();
int numLines = _myRichTextBox.Lines.Count();
if (numLines > growIfMoreThan)
{
int width = _myForm.Size.Width;
int height = _myForm.Size.Height;
int newHeight = height + ((numLines - growIfMoreThan) * pixelsPerLine);
if (newHeight > maxHeight)
{
newHeight = maxHeight;
}
_myForm.Size = new System.Drawing.Size(width, newHeight);
}
//_myRichTextBox.Hide(); // Sanity test -- works
//_myRichTextBox.Visible = false; // Sanity test -- works
// NONE OF THE FOLLOWING WORK AFTER FORMREGION DISPLAYED:
//_myForm.RichTextBox1.Show();
//_myRichTextBox.Show();
//_myForm.RichTextBox1.Visible = true;
//_myRichTextBox.Visible = true;
//_myForm.RichTextBox1.CreateControl();
//_myForm.RichTextBox1.BringToFront();
//_myForm.RichTextBox1.Update();
//_myForm.Update();
//RichTextBox testBox = new RichTextBox();
//testBox.AcceptsTab = true;
//testBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
//| System.Windows.Forms.AnchorStyles.Left)
//| System.Windows.Forms.AnchorStyles.Right)));
//testBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
//testBox.Font = new System.Drawing.Font("Segoe UI", 9.75F);
//testBox.ImeMode = System.Windows.Forms.ImeMode.Off;
//testBox.Location = new System.Drawing.Point(6, 23);
//testBox.Name = "richTextBox2";
//testBox.ReadOnly = true;
//testBox.Size = new System.Drawing.Size(698, 133);
//testBox.TabIndex = 11;
//testBox.TabStop = false;
//testBox.Text = "";
//testBox.Rtf = _processedRTFText;
//testBox.BringToFront();
//testBox.Update();
//testBox.Show();
//testBox.Visible = true;
//_myForm.Controls.Add(testBox);
//_myForm.GroupBox1.PerformLayout();
//_myForm.PerformLayout();
DialogResult result = _myForm.ShowDialog();
//testBox = null;
return result;
}

Auto Scroll Table Layout Panel does not start at top

I am working on a very simple table layout application for getting started with learning C#. I am doing everything programmatic ally ( not through design editor)
I am trying to add scrolling onto the application. It seems to work fine, but it does not seem to start at the top of the horizontal range by default. I tried adding things like Max/min size, autoscroll margins etc., but nothing seems to have the desired effect. I am sure there is something simple I am missing.
Here is my current code as it relates to the problem.
layout = new TableLayoutPanel();
layout.Height = 1075;
layout.Width = 704;
layout.Name = "masterLayout";
layout.Dock = DockStyle.Fill;
layout.AutoScroll = true;
int i = 0;
foreach (Race r in ELECTION_DATA.races.OrderBy(o => o.race_id)) {
layout.Controls.Add(new Label { AutoSize = true, Text =r.race_id, Name=r.race_id, Width=300}, i, 0 );
layout.Controls.Add(new TreeView { AutoSize = true, Text = r.race_id, Name = r.race_id, Height = 1000, Width = 300 }, i,1);
i += 1;
}
Controls.Add(layout);
Here is an image, The Label Control Is not visible because the scroll is offset to the beginning of the tree view.
How can I ensure the scroll always starts at the very top?
The ScrollLayoutPanel has a method called ScrollControlIntoView that will move a specific control inside the panel into view. If you just scroll your first control into the view after you are done filling your panels, then that should ensure that the top is visible. In other words:
// do your loop first...
foreach (...)
{
layout.Controls.Add(...);
}
// then if any controls exist, scroll the first control into view
if (layout.Controls.Count > 0)
{
layout.ScrollControlIntoView(layout.Controls[0]);
}

Align dynamically added controls horizontally and vertically within a control in c# winforms

I have this program that dynamically adds pictureboxes referring to the number of president in the database. How do i put them inside the groupbox and align the pictureboxes inside the groupbox? And the groupbox should stretch if the pictureboxes are many.
I have this codes now :
private void Form1_Load(object sender, EventArgs e)
{
conn.Open();
try
{
cmd = new SqlCommand("SELECT COUNT(Position) FROM TableVote WHERE Position='" + "President" + "'", conn);
Int32 PresCount = (Int32)cmd.ExecuteScalar();
TxtPresCount.Text = PresCount.ToString();
for (int i = 0; i < PresCount; ++i)
{
GroupBox PresGB = new GroupBox();
{
PresGB.Size = new Size(491, 152);
PresGB.Location = new Point(12, 12);
PresGB.Text = "President";
this.Controls.Add(PresGB);
PresGB.SendToBack();
PictureBox PresPB = new PictureBox();
PresPB.Location = new Point(80 + (150 * i) + 20, 50);
PresPB.Size = new Size(75, 75);
PresPB.BorderStyle = BorderStyle.Fixed3D;
PresPB.ImageLocation = "imgPath";
this.Controls.Add(PresPB);
PresPB.BringToFront();
};
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
conn.Close();
}
}
I would want the pictureboxes to be inside the groupbox and align it inside.
Maybe the FlowLayoutPanel control already does what you are trying to do. Just create your picture boxes and add them to a FlowLayoutPanel instead of a GroupBox.
FlowLayoutPanel automatically arranges controls in rows and/or columns depending on the value of its FlowDirection property. Set myFlowLayoutPanel.FlowDirection = FlowDirection.TopDown to get a vertical arranged list.
If you don't want multiple rows or columns set the WrapContents property to false. You can also set the AutoScroll property to true to automatically get scrollbars if the controls don't fit.
If you prefer to have the border of a GroupBox you can still put the FlowLayoutPanel into a GroupBox.
To adjust the space between the picture boxes you can use the Margin property.
This gives you a lot of control over the layout and you don't need to calculate the control positions. Also, if the size of the FlowLayoutPanel changes everything is rearranged automatically.
UPDATE:
I have a few comments on your code:
The curly braces make this look like the syntax of an object initializer - but it isn't.
GroupBox PresGB = new GroupBox(); // this line ends with a semicolon
{
// therefore this is just a block of code not related to new GroupBox()
};
You should remove the curly braces.
The creation of the group box is inside the loop. I doubt that you want a new group box for each picture box. This is the reason why you only see a single picture. Each new group box hides all the previous ones.
You add the picture boxes to the form instead of the group box.
You use "cryptic" names. PresGB and PresPB are very likely to be swapped accidentally. Abbreviations are usually a bad choice for names.
You don't need to call SendToBack or BringToFront since you don't want the controls to overlap anyway.
I don't think GroupBox is a good choice. Of course you can make it bigger if the number of pictures increases but you are limited by the screen and you don't get scollbars if the picture boxes don't fit. Use a FlowLayoutPanel. It has all the "magic" that you are looking for.
Replace your for loop with this piece of code:
var panel = new FlowLayoutPanel();
panel.SuspendLayout(); // don't calculate the layout before all picture boxes are added
panel.Size = new Size(491, 152);
panel.Location = new Point(12, 12);
panel.BorderStyle = BorderStyle.Fixed3D;
panel.FlowDirection = FlowDirection.LeftToRight;
panel.AutoScroll = true; // automatically add scrollbars if needed
panel.WrapContents = false; // all picture boxes in a single row
this.Controls.Add(panel);
for (int i = 0; i < PresCount; ++i)
{
var pictureBox = new PictureBox();
// the location is calculated by the FlowLayoutPanel
pictureBox.Size = new Size(75, 75);
pictureBox.BorderStyle = BorderStyle.FixedSingle;
pictureBox.ImageLocation = "imgPath";
panel.Controls.Add(pictureBox);
}
panel.ResumeLayout();
You can always drop a control on your form, do what you want to do then look at the designer generated code to see how the designer does it (in the "Designer.cs" file). Behind the scenes it is loading all controls and setting all properties via code.
That being said.
Keep in mind that once you put your picturebox inside the groupbox all location coordinate are in relation to the groupbox. So "0,0" is the upper-left corner of the groupbox, not the form.
To anchor your picturebox use the following code (this is just a straight copy-paste from my designer generated code, so you can clean it up a bit):
this.PresPB.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
To dock your picture box (so it fills the entire containing control):
this.PresPB.Dock = System.Windows.Forms.DockStyle.Fill;
You also need to change this line:
this.Controls.Add(PresPB);
to this:
PresGB.Controls.Add(PresPB);

How do you resize a form to fit its content automatically?

I am trying to implement the following behaviour:
On a form there is a tabcontrol. On that tabcontrol there is a treeview. To prevent scrollbars appearing, I would like the form to change its size according to the contents of the treeview when displayed for the first time.
If the treeview has too many nodes to be displayed on the default size of the form, the form should change it's size so that there is no vertical scrollbar on the treeview (up to a maximum size allowed by the size of the screen).
What I need to know is, if it is possible to achieve this behaviour through the properties of the controls. I'm sure this can be achieved by calculating and settings the sizes of the elements programmatically, but I would like to know if there is a way to achieve this by settings like AutoSizeMode etc.
[UPDATE]
It's the first dialog a user of my application sees: It's a dialog to select the database to work with. It's a list of databases, with a tabcontrol, buttens etc. If the list is too long, scrollbars appear and a colleague of mine wants them to disappear.
Use the AutoSize and AutoSizeMode properties.
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.autosize.aspx
An example:
private void Form1_Load(object sender, EventArgs e)
{
// no smaller than design time size
this.MinimumSize = new System.Drawing.Size(this.Width, this.Height);
// no larger than screen size
this.MaximumSize = new System.Drawing.Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, (int)System.Windows.SystemParameters.PrimaryScreenHeight);
this.AutoSize = true;
this.AutoSizeMode = AutoSizeMode.GrowAndShrink;
// rest of your code here...
}
By using the various sizing properties (Dock, Anchor) or container controls (Panel, TableLayoutPanel, FlowLayoutPanel, etc.) you can only dictate the size from the outer control down to the inner controls. But there is nothing (working) within the .Net framework that allows to dictate the size of a container through the size of the child control. I also missed this a few times and tried the AutoSize property, but it never worked.
So all you can do is trying to get this stuff done manually, sorry.
From MSDN:
To maximize productivity, the Windows Forms Designer shadows the
AutoSize property for the Form class. At design time, the form
behaves as though the AutoSize property is set to false,
regardless of its actual setting. At runtime, no special
accommodation is made, and the AutoSize property is applied as
specified by the property setting.
This might be useful.
It resizes a new form to a user control, and then anchors the user control to the new form:
Form f = new Form();
MyUserControl muc = new MyUserControl();
f.ClientSize = muc.Size;
f.Controls.Add(muc);
muc.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
f.ShowDialog();
You could calculate the required height of the TreeView, by figuring out the height of a node, multiplying it by the number of nodes, then setting the form's MinimumSize property accordingly.
// assuming the treeview is populated!
nodeHeight = treeview1.Nodes[0].Bounds.Height;
this.MaximumSize = new Size(someMaximumWidth, someMaximumHeight);
int requiredFormHeight = (treeView1.GetNodeCount(true) * nodeHeight);
this.MinimumSize = new Size(this.Width, requiredFormHeight);
NB. This assumes though that the treeview1 is the only control on the form. When setting the requiredFormHeight variable you'll need to allow for other controls and height requirements surrounding the treeview, such as the tabcontrol you mentioned.
(I would however agree with #jgauffin and assess the rationale behind the requirement to resize a form everytime it loads without the user's consent - maybe let the user position and size the form and remember that instead??)
This technique solved my problem:
In parent form:
frmEmployee frm = new frmEmployee();
frm.MdiParent = this;
frm.Dock = DockStyle.Fill;
frm.Show();
In the child form (Load event):
this.WindowState = FormWindowState.Maximized;
If you trying to fit the content according to the forms than the following will help. It helps me while I was trying to fit the content on the form to fit when ever the forms were resized.
this.contents.Size = new Size(this.ClientRectangle.Width,
this.ClientRectangle.Height);
I User this Code in my project, Useful for me.
private void Form1_Resize(object sender, EventArgs e)
{
int w = MainPanel.Width; // you can use form.width when you don't use panels
w = (w - 120)/4; // 120 because set 15px for each side of panels
// and put panels in FlowLayoutPanel
// 4 because i have 4 panel boxes
panel1.Width = w;
panel2.Width = w;
panel3.Width = w;
panel4.Width = w;
}
I used this code and it works just fine
const int margin = 5;
Rectangle rect = new Rectangle(
Screen.PrimaryScreen.WorkingArea.X + margin,
Screen.PrimaryScreen.WorkingArea.Y + margin,
Screen.PrimaryScreen.WorkingArea.Width - 2 * margin,
Screen.PrimaryScreen.WorkingArea.Height - 2 * (margin - 7));
this.Bounds = rect;

Winforms, creating padding when using Dock properties

How do I add padding, or some space between the textboxes when using dockstyle.top property?
for(int i =0; i< 10; i++) {
textboxes[i] = new TextBox();
textboxes[i].Dock = DockStyle.Top;
mypanel.Controls.Add(textboxes[i]);
}
The code above puts textboxes right beneath each other. Can't figure this out without using mass panels or fixed positioning. How to do the following?
1) I would like to add around 10-20pixels between boxes.
2) How to change size (height,width) of the textboxes, since when using dockstyle.top it ignores the size commands ?
With DockStype.Top you can't change the width of your TextBoxes, cause they are docked. You can only change the height. But to change the height of a TextBox you have to set the Multiline = true beforehand.
To get the space between the different boxes you have to put each TextBox within a panel, set the TextBox.Dock = Fill, the Panel.Dock = Top and the Panel.Padding = 10. Now you have some space between each TextBox.
Sample Code
for (int i = 0; i < 10; i++)
{
var panelTextBox = CreateBorderedTextBox();
this.Controls.Add(panelTextBox);
}
private Panel CreateBorderedTextBox()
{
var panel = CreatePanel();
var textBox = CreateTextBox();
panel.Controls.Add(textBox);
return panel;
}
private Panel CreatePanel()
{
var panel = new Panel();
panel.Dock = DockStyle.Top;
panel.Padding = new Padding(5);
return panel;
}
private TextBox CreateTextBox()
{
var textBox = new TextBox();
textBox.Multiline = true;
textBox.Dock = DockStyle.Fill;
return textBox;
}
What i forgot, you can also give a try to the FlowLayoutPanel. Just remove the DockStyle.Top from the panels and put them into the FlowLayoutPanel. Also you should set the FlowDirection to TopDown. Maybe this can also help you to solve your problem, too.
Another work around that suits smaller layouts is to just add a Label control afterwards also docked to the Top, which is not AutoSized, Text=" ", Height=your padding. This is quite useful for the odd bit of padding when using the designer.
I know where you're coming from, this is especially frustrating after returning to WinForms from WPF.
I would suggest using a TableLayoutPanel, in which each TextBox would get its own cell, and adjusting the properties of the cells. This should solve both your padding and size problems.
Another alternative would be to use some more complex layout controls, such as the DevExpress ones (not free).

Categories

Resources