Change row/column span programmatically (tablelayoutpanel) - c#

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.

Related

How to detect if a mouse event is on the row divider or on the row itself

I have a DataGridView with rows that I group based on group number. To visually separate the rows of different groups, I set the DividerHeight of the last row in a certain group.
I want to implement a different behaviour for mouse events for row dividers and the rows themselves. DataGridView.HitTestInfo doesn't seem to have a way of checking this. Is there any way for me to find out if a row divider was clicked or if anything was dropped on it?
An image of how my grid looks. (dark grey areas are the row dividers):
The DataGridView HitTest() method returns information related to the Row at the specified client coordinates (coordinates relative to the DataGridView Client area).
You can use the MouseDown event of the DataGridView to determine the Mouse coordinates (MouseEventArgs already returns Mouse coordinates relative to the Control's Client area).
If the Hit Test is successful, you can use its RowIndex Property to determine the bounds of the Row under the Mouse Pointer, calling DataGridView.GetRowDisplayRectangle()
With this information, you can compare the position of the Mouse Pointer in relation to the bounds of the Row and the area occupied by the divider
The divider is part of the Row's bounding rectangle
Subtract the height of the divider ([Row].DividerHeight) from the [Row].Bounds.Bottom value and verify whether the Mouse Y position is greater than this value.
For example:
private void someDataGridView_MouseDown(object sender, MouseEventArgs e)
{
var dgv = sender as DataGridView;
var test = dgv.HitTest(e.X, e.Y);
if (test.RowIndex == -1) return;
var row = dgv.Rows[test.RowIndex];
var rowBounds = dgv.GetRowDisplayRectangle(test.RowIndex, false);
bool isDivider = e.Y >= (rowBounds.Bottom - row.DividerHeight);
}
Adapt as required in case custom painting is in place

C# Chart: Multiple questions about ChartAreas.Cusor and reading X/Y values

I have a program running on a server which contacts Online-APIs for their Data every 5 seconds. The data gets saved in a Database as pairs. One pair consists of a UNIX-Timestamp and a double value.
In my C# application, I want to show the values of 2 APIs at the same time. The X-Axis contains the timestamps and the Y-Axis the double values. It is guaranteed that both series have the same X-Values - only the Y-Values are different. It looks like this:
You can see that I already added the ChartArea[0].CursorX to the chart (the green line). It gets updated like this:
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
Point p = new Point(e.X, e.Y);
chart1.ChartAreas[0].CursorX.SetCursorPixelPosition(p, true);
DateTime t = DateTime.FromOADate(chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X));
graph_time.Text = t.ToLongTimeString();
}
So the green CursorX gets set to the X position of the mouse. However, I set its interval to 5 Seconds.
First Question
I'm trying to show the X-Value of the CursorX in a label with these lines
DateTime t = DateTime.FromOADate(chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X));
graph_time.Text = t.ToLongTimeString();
The problem is, it shows the X-Value from the position of the real cursor (which I'm hiding) instead of the green line. How can I get the value on the X-Axis of the green line?
Second Question
I also want to show the value of the intersections of the Green/Blue and Green/Red lines in two seperate Labels. Does anyone have a idea how to do that? I read about HitTest, but you need a X and Y value for it. I'd need something like a Vertical HitTest.
Third and last question
Is there any possibility to bind the green line (ChartArea.CursorX) to the actual exisiting DataPoints instead of setting a interval? Because there are two problems with it: 1. When the pairs for the chart look like this (timestamp,value) {2, 1.23}, {7, 43.2}, {12, 5.3} and the CursorX interval is set to 5 seconds, the CursorX stops at X = 0,5,10 instead of X = 2,7,12.
2. Sometimes the time difference between two pairs is not excatly 5 seconds, it can sometimes be 4 or 6. That's very a 5 second interval creates mistakes - because I want the CusorX only to stop at the exisiting DataPoints.
So, thats it. I tried the Charts in C# for the first time today and a lot of cool ideas came into my head - with a lot of problems to realize them. Hopefully some of you are good at C# charts and can help me out :)
Thanks!
Let me try to answer without testing..:
1 - Use CursorX.Position to get at the x-value the cursor sits on
2 - Find the two data points before and after the cursor and interpolate their Y-values. You can use LINQ to find the two points.. See here for an example how to search in the points collection.
3 - See 2! Pick the first or second or closest point; you need to set the Interval to 0 for this.
I tried around a little bit yesterday evening and the solution for my problem is actually way easier than I thought. It pretty much works like the answer from TaW
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
if (e.X < 0 || e.Y < 0 || e.Location == prevPos)
return;
prevPos = e.Location;
if (this.graphShowingData == false)
return;
Point p = new Point(e.X, e.Y);
double searchVal = chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X);
foreach (DataPoint dp in chart1.Series["Series1"].Points)
{
if(dp.XValue >= searchVal)
{
chart1.ChartAreas[0].CursorX.SetCursorPosition(dp.XValue);
foreach(double yD in dp.YValues)
{
val_series1.Text = Math.Round(yD, 4).ToString();
}
break;
}
}
foreach (DataPoint dp in chart1.Series["Series2"].Points)
{
if (dp.XValue >= searchVal)
{
foreach (double yD in dp.YValues)
{
val_series2.Text = Math.Round(yD, 4).ToString();
}
break;
}
}
DateTime t = DateTime.FromOADate(chart1.ChartAreas[0].CursorX.Position);
graph_time.Text = t.ToLongTimeString();
}
This code solves all of my three questions above.

How to set picture box height in percentage?

I have a tablelayout panel and it has 3 rows first row is 70 percent and remaining 2 is 15 percent each.
in the first row i put a picture box and i dock it top but i want it's height to be the height of the row i put in.
I am trying it like this but it takes the height in int. And instead of 70% it accepts 70.
So how can i set it's height in percent.
public CtrlBasketItems()
{
InitializeComponent();
pictureBox1.Height = (int)(tableLayoutPanel1.RowStyles[0].Height);
}
pictureBox1.Height = (int)(tableLayoutPanel1.Height * 0.7)
Then you would have to position it in the row as needed, of course
Set your PictureBox to be Dock = Fill instead: your picture box will fill the cell it occupies (i.e. be the same height as the cell/row).

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

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

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.

Categories

Resources