Why don't controls placed in TableLayoutPanels "snap to" their "cells"? - c#

I am dynamically creating a TableLayoutPanel, and then dynamically creating Labels and TextBoxes to put inside it.
It would seem logical that I could just assign the number of columns and rows to the TableLayoutPanel:
tableLayoutPanelGreatGooglyMoogly = new TableLayoutPanel();
tableLayoutPanelGreatGooglyMoogly.RowCount = NUMBER_OF_ROWS;
tableLayoutPanelGreatGooglyMoogly.ColumnCount = NUMBER_OF_COLUMNS;
...create the controls to place inside it:
Label lbl = new Label();
lbl.Parent = tableLayoutPanelGreatGooglyMoogly;
. . .
...and then put the created control[s] in the specified "cell" (column and row):
tableLayoutPanelGreatGooglyMoogly.SetColumn(lbl, ACol); // "ACol" is the current column
tableLayoutPanelGreatGooglyMoogly.SetRow(lbl, i); // "i" is the current row
...but that's not working - neither if I specify the width and height values for the dynamically created child controls or if I don't (in which case they are too large - specifically, their width is too great).
UPDATE
I added this code, and it makes no difference:
// ROWS
tableLayoutPanelGreatGooglyMoogly.RowCount = NUMBER_OF_ROWS;
TableLayoutRowStyleCollection rowStyles =
this.tableLayoutPanelGreatGooglyMoogly.RowStyles;
foreach (RowStyle rStyle in rowStyles) {
rStyle.SizeType = SizeType.Percent;
rStyle.Height = 8;
}
// COLUMNS
tableLayoutPanelGreatGooglyMoogly.ColumnCount = TOTAL_NUMBER_OF_COLUMNS;
TableLayoutColumnStyleCollection columnStyles =
this.tableLayoutPanelGreatGooglyMoogly.ColumnStyles;
foreach (ColumnStyle cStyle in columnStyles) {
cStyle.SizeType = SizeType.Percent;
cStyle.Width = 12;
}
UPDATE to the UPDATE
I see that at design-time, a Label or TextBox (presumably, any control) has a Cell[col,row] property. I would like to access that dynamically, if it is not readonly, so that I could set:
lbl.Cell = i,i
txtbox.Cell = i+1,i
Is that possible to do in code? The "Cell" property does not seem to be recognized (understandably, I guess) at that time.
UPDATE to the UPDATE REVISITED
I added this line of code:
tableLayoutPanelGreatGooglyMoogly.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single;
...and now I see that the labels and textBoxes actually are in the cells (columns and rows) I'm expecting them to inhabit.
However, I need to get the labels to move down from the upper left corner of their cells to the center of the cell (both vertically and horizontally).
Even at design time (with a "test"/temporary TableLayoutPanel on the form), added Labels do not respond to changes to the TextAlign property when they are sitting inside a TableLayoutPanel cell - no matter what I set TextAlign to ("Middle Center" seems the most sensible), they stubbornly remain affixed to the top left of the cell.
Similary, changing the Labels' Location.X and Location.Y at design time does nothing. The Labels stick to the NW corner of the cell like a barnacle to a long-lost anchor.

An important part of using the GridLayoutPanel that is rarely mentioned is the use of the Anchor property in child controls.
The Anchor property determines which edge of the cell each child control will extend to.
When you create your labels you do it like this:
Label lbl = new Label();
lbl.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
lbl.Parent = tableLayoutPanelGreatGooglyMoogly;
It should stretch the labels to the full size of the cell.
See http://msdn.microsoft.com/en-us/library/w4yc3e8c(v=vs.80).aspx in the "Positioning Controls Within Cells Using Docking and Anchoring" secton.

Related

How to put a button at center of column in stackpanel

I am c# silverligth developer.
I have a grid which contains 1 row and 3 columns.Inside each column i have a stackpanel and on that stackpanel i display the textblock.I do so because it looks good and i have more space and i can display more then 1 item in 1 cell of grid using this stackpanel.
My code to do so is:
TextBlock txtblkLabel = new TextBlock();
txtblkLabel.Text = param.Label;
StackPanel sp1 = new StackPanel();
sp1.Orientation = Orientation.Horizontal;
sp1.Children.Add(txtblkLabel);
sp1.Width = 50;
sp1.Height = 50;
Grid.SetRow(sp1, LoopCount);
Grid.SetColumn(sp1, 2);
g.Children.Add(sp1);
Now the display is at the top left but i want to have this text display at center.
How to achieve it in c# code (not xaml) ?
You can try this,
txtblkLabel.VerticalAlignment = System.Windows.VerticalAlignment.Center;
txtblkLabel.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
txtblkLabel.TextAlignment = System.Windows.TextAlignment.Center;
You cannot have Controls aligned in the middle of the StackPanel. StackPanel is not meant to have controls being centered in it. It is meant to have controls stacked in it, i.e. one after another.
You could either fill your StackPanel with the TextBlock and than have text centered that way or you could use another Grid instead of StackPanel or some other solution...

three panels layout on form [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I'm trying to construct a form layout, which will meet following requirements:
panel1 is fixed height - it will contain only a label which will be some kind of header with title, etc
panel2 will contain datagridview with dockstyle fill, here user will find objects which he can select to show their properties
panel3 is fixed height - it will be positioned at the bottom of the form and will contain properties of selected object from the datagridview
My problem is to make panel2 to to fill the whole place which left after panel1 and panel3. So if panel1 and panel3 has both fixed height 100, and the form has height 500, then panel2 should have 300 height, if form will be resized to 600, then panel2 should also resize to 400, etc.
I was trying some dock combinations, trying to set panel1 dock as top, panel3 as bottom and panel2 as fill, but it gives other results than expected. I know I can handle the form resize event and resize panel2 to a size which will left, but I'm wondering if there's some more elastic and clean way to do this.
The docking space is related to the order of objects on your form as im_a_noob has mentioned. You can change object z-order to change how they dock. You should be able to right-click the panel that needs to fill the space in the middle and then select "Bring to Front" from the menu. That should make it fill the space correctly and the whole form behind the other panels.
So you would dock your top panel to the top, bottom panel to the bottom, and then the center one to "Fill". Then right-click and bring the center one to the front.
this is because of the Document Outline.
go to
View -> Other Windows -> Document Outline (or ctrl + w, u)
make sure your dock fill pannel (middle one) is the first of the 3 pannel in that list. This should fix you.
It seems like a tableLayoutPanel would be a good choice here. That way you have the ability to set absolute values for row 1 (panel 1) and row 3 (panel 3) and then use 100% for the middle row (panel 2) guaranteeing that it will take up the remaining space without overlapping the other panels.
Then once you put your datagridview into the middle row of the tableLayoutPanel you should be able to set the Dock property to fill and it should work correctly.
TableLayoutPanels only allow for one element to be placed in a cell, however you can get around this by adding a panel as the main element and then configure everything in that panel.
Just set the panel1 anchors as top, left, right; panel 2 anchors to be top, bottom, left, right; panel 3 anchors bottom, left, right. This will ensure that the top panel stays in place, bottom moves down with the window and middle will expand in between.
First, Dock Panels 1 and 3 (Panel 1 to Top, Panel 3 to Bottom):
Once those two are set, select Panel 2 and set it to Fill:
UPDATE:
Here is a quick piece of code I did to verify your panels are in the right order in your code:
public partial class PanelForm : Form {
public PanelForm() {
InitializeComponent();
int iHead = Controls.GetChildIndex(panelHead);
int iData = Controls.GetChildIndex(panelData);
int iFoot = Controls.GetChildIndex(panelFoot);
if ((iHead < iData) || (iFoot < iData)) {
panelHead.Dock = DockStyle.None;
panelData.Dock = DockStyle.None;
panelFoot.Dock = DockStyle.None;
Controls.SetChildIndex(panelData, 0);
Controls.SetChildIndex(panelHead, 1);
Controls.SetChildIndex(panelFoot, 2);
panelData.Dock = DockStyle.Fill;
panelHead.Dock = DockStyle.Top;
panelFoot.Dock = DockStyle.Bottom;
}
ShowData(DateTime.Now);
}
private void ShowData(DateTime now) {
var table = new DataTable();
var c1 = table.Columns.Add("Name", typeof(string));
var c2 = table.Columns.Add("Even", typeof(bool));
var c3 = table.Columns.Add("Index", typeof(int));
var c4 = table.Columns.Add("Times 2", typeof(int));
var c5 = table.Columns.Add("Inverse", typeof(double));
var c6 = table.Columns.Add("Timespan", typeof(TimeSpan));
var c7 = table.Columns.Add("Binary Time", typeof(long));
var c8 = table.Columns.Add("Display", typeof(string));
for (int i = 0; i < 1000; i++) {
DataRow r = table.NewRow();
r[c1] = string.Format("Row {0}", i);
r[c2] = (i % 2 == 0);
r[c3] = i;
r[c4] = 2 * i;
r[c5] = (0 < i) ? 1 / (double)i : double.NaN;
r[c6] = DateTime.Now - now;
r[c7] = DateTime.Now.ToBinary();
r[c8] = string.Format("{0:g}", DateTime.Now);
table.Rows.Add(r);
}
dataGridView1.DataSource = table;
}
}

Fix row height of every row in TableLayoutPanel

I'm working on Windows c#.
Firstly, the things those can not be change as my need are following:
The Size of TableLayoutPanel is fixed.
The Total # of columns are fixed.
Now, I want to set a fix height for all rows but as increasing the rows, if I set the RowStyle property to Percent with 100.0F then it works fine for 3 to 4 items, but after 4-5 items, the control on one row overwrites controls on another row.
I have searched for this so more but i'm not able to get the proper answer. I have also tried the AutoSize, Percent, Absolute properties of RowStyle, even though it is not working.
So what to do and how? How can I achieve this?
Ultimately, I want to do same like as DataGridView of Windows C#.
Thanks in advance....
I'm working on WinForms...the sample code is here..
int cnt = tableLayout.RowCount = myDataTable.Rows.Count;
tableLayout.Size = new System.Drawing.Size(555, 200);
for (int i = 1; i <= cnt; i++)
{
Label lblSrNo = new Label();
lblSrNo.Text = i.ToString();
TextBox txt = new TextBox();
txt.Text = "";
txt.Size = new System.Drawing.Size(69, 20);
tableLayout.Controls.Add(lblSrNo, 0, i - 1);
tableLayout.Controls.Add(txt, 1, i - 1);
}
tableLayout.RowStyles.Clear();
foreach (RowStyle rs in tableLayout.RowStyles)
tableLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
The label and textboxes are working fine for 4-5 #of rows but whenever the #of row(in this case, variable cnt in for loop) increases, the rows are overwriting each other that is one control overwrite to another...I had drag-drop the TableLayoutPanel control and created just one row and 2 columns manually.
So please tell me how to do it.
I'm still new to tableLayoutPanels myself, but I noticed that at the bottom of your code, you're Clearing all the rowstyles from the collection, then you're trying to iterate through them in your foreach loop.
You did this:
tableLayout.RowStyles.Clear(); //now you have zero rowstyles
foreach (RowStyle rs in tableLayout.RowStyles) //this will never execute
tableLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
Try this instead.
TableLayoutRowStyleCollection styles =
tableLayout.RowStyles;
foreach (RowStyle style in styles){
// Set the row height to 20 pixels.
style.SizeType = SizeType.Absolute;
style.Height = 20;
}
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Edit: I just realized that adding N rows doesn't add N rowstyles that you can iterate through. I think what's happening is that you're adding N rows, but none of them have a rowstyles.
I suppose you can Clear() the rowstyles, then just add N rowstyles similar to how you're already doing.
There are 2 ways to increase the row height of table layout panel.
Look into the following link :
https://social.msdn.microsoft.com/Forums/windows/en-US/d80db8e1-d6cc-48b8-957f-0f73263c6d4a/how-to-change-the-row-height-of-a-tablelayoutpanel-at-runtime?forum=winforms
It specifies by setting the YourTableLayoutPanel.RowStyles[index].Height int he code behind class.
The other way is to set the row height in the designer of your UI. Through UI, go into Rows properties of the panel, select the row and set the required height using percent or absolute

Listview items text is trucncated and doesn't show it all

I am usign a code a code like this and when the text gets long, it cuts it off and doesn't show the whole text :( In this aspect I want it to behave like a list box item. One line was for one item in the list box and didn't have this trucnacted text issue.
listView1.Scrollable = true;
listView1.View = View.Details;
listView1.HeaderStyle = ColumnHeaderStyle.None;
ColumnHeader header = new ColumnHeader();
header.Text = "MyHeader";
header.Name = "MyColumn1";
listView1.Columns.Add(header);
listView1.Items.Add("TooLongTextDoesntShow");
listView1.Items.Add("short");
listView1.Items.Add("abcd");
I think it is just easier to attach a picture of the issue. Please notice how it is not displaying full text of the highlighted item :(
Thanks for your help.
Just specify a column header width.
ColumnHeader header = new ColumnHeader();
header.Text = "MyHeader";
header.Name = "MyColumn1";
header.Width = listView1.Width //Same Width as Entire List Control
listView1.Columns.Add(header);
Alternative ways to do, is during the add.
You can make use of: ListView.ColumnHeaderCollection.Add
public virtual ColumnHeader Add(
string text,
int width //width of the header
)
Ok, I found a solution, please let me know if there are better ways of doing it too
AFTER adding items to list view is done, we should call this:
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
We take an example of ListView with 2 columns and resize on contents and then to minimum width.
// Auto resize of ListView Columns to minimum width
private int[] ColumnsWidth = { 35, 322 };
/// <summary>
/// Resize the columns based on the items entered
/// </summary>
private void ResizeColumns()
{
// Auto Resize Columns based on content
m_urlsListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
// Make sure to resize to minimum width
if (m_urlsListView.Columns[0].Width < ColumnsWidth[0])
{
m_urlsListView.Columns[0].Width = ColumnsWidth[0];
}
if (m_urlsListView.Columns[1].Width < ColumnsWidth[1])
{
m_urlsListView.Columns[1].Width = ColumnsWidth[1];
}
}
The content is being truncated because of (practically invisible) column. You can tell the ListView to adjust the column widths automatically:
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
You can just add a column and define its width according to your text size requirement. Moreover "Scrollable" property can be set to true if the actual width of the listview control is smaller
ListView_Column_Width_Image

Change row/column span programmatically (tablelayoutpanel)

I have a tablelayoutpanel. 2x2 - 2 columns 2 rows.
For example, I added a button button1 in a 1 row, second column. button1 has a dock property set to Fill. VS Designer allows to set column/row span properties of button1.
I want an availability to change row span property of button1 programatically, so it can fill all second column(1 row and second row) and availability to set it back.
How?
What about this code?
private void button1_Click(object sender, EventArgs e)
{
var control = sender as Control;
if(control == null)
return;
if (1 == tableLayoutPanel1.GetRowSpan(control))
{
tableLayoutPanel1.SetRowSpan(control, 2);
}
else
{
tableLayoutPanel1.SetRowSpan(control, 1);
}
}
While I find the current up-voted answer quite adequate, it also appears slightly messier than need be. You must add the controls to the tableLayoutPanel before setting their properties.
Visual Studio (2013 and likely other versions) will show these properties as part of the control. When in reality, they are part of the tableLayoutPanel.
Explanation:
tableLayoutPanel.Controls.Add(**control**, x, y)
tableLayoutPanel.SetColumnSpan(**control**, '# of cols to span')
Example:
tableLayoutPanel1.Controls.Add(**button1**, 0, 0);
tableLayoutPanel1.SetColumnSpan(**button1**, 2);
tableLayoutPanel1.SetRowSpan(**button1**, 3);
Result: A button which 'occupies' this space. (Provided it is large enough to cover the area. Even if it does not 'cover' the space, it will still 'reserve' it.)
O O X X X
O O X X X
O O X X X
X X X X X
X X X X X
Setting the span larger than the size of the grid will.. :
NOT change the grid size.
NOT crop/edit the number to the size of the grid.
NOT throw an error at compile.
It WILL act/perform as if the span was set to the current grid (tableLayoutPanel) maximum size. This is only relevant if the TLP/grid size changes.
If you add two controls two the same grid location programmatically, the first control in a grid keeps its location. Any subsequently added control gets pushed to the next cell block. If a 'span' is added, it will treat that cell block as used and continue searching for an unused cell block.
Ex: label1, label2 and label3 are added to 0,0.
label1 will appear in 0,0
label2: 0,1
label3: 0,2
Ex 2: label 1 has a row span of 2.
label1: 0,0
label2: relocated to 0,2
label3: 0,3
After you have selected the correct grid point and spans, you can then further optimize your layout using the dock and anchor properties.

Categories

Resources