I'm trying to create a panel(Static) in C#, were I generate multiple ListViews/GridViews in a Grid.
I know how to Fill a single existing ListView.
I've done this multiple times on ListViews I dragged onto my application using the toolbox.
I have a sqldatabase connection and I want to use data from that database to determine how many ListViews/GridViews are going to be generated.
I found a picture of what I am imagining in my head(Without the roomstatus)
If there are more ListViews/GridViews generated I want to be able to scroll down INSIDE the panel i created.
Okay, i've managed to pull it of!
private void GenerateTable()
{
SomerenLogic.Room_Service roomService = new SomerenLogic.Room_Service();
List<Room> roomList = roomService.GetRooms();
int counter = 0;
foreach (SomerenModel.Room s in roomList)
{
counter = counter + 1;
}
double wortelvan = Math.Sqrt(counter);
double column = Math.Floor(wortelvan);
double row = Math.Ceiling(wortelvan);
int columnCount = (int)(column);
int rowCount = (int)(row);
SomerenLogic.Indeling_Service indelingService = new SomerenLogic.Indeling_Service();
//Clear out the existing controls, we are generating a new table layout
tableLayoutPanel1.Controls.Clear();
tableLayoutPanel1.RowStyles.Clear();
//Clear out the existing row and column styles
tableLayoutPanel1.ColumnStyles.Clear();
tableLayoutPanel1.RowStyles.Clear();
//Now we will generate the table, setting up the row and column counts first
tableLayoutPanel1.ColumnCount = columnCount;
tableLayoutPanel1.RowCount = rowCount;
int counter2 = 1;
for (int x = 0; x < columnCount; x++)
{
//First add a column
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent));
for (int y = 0; y < rowCount; y++)
{
//Next, add a row. Only do this when once, when creating the first column
if (x == 0)
{
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent));
}
////Create the control, in this case we will add a button
//Button cmd = new Button();
//cmd.Text = string.Format("({0}, {1})", x, y);
////Finally, add the control to the correct location in the table
ListView listView1 = new ListView();
listView1.Columns.Add("");
listView1.View = View.Details;
listView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
listView1.Scrollable = false;
listView1.GridLines = true;
listView1.AutoArrange = true;
List<Indeling> indelingList = indelingService.GetIndeling(counter2);
foreach (SomerenModel.Indeling s in indelingList)
{
ListViewItem la = new ListViewItem("Kamer nummer: "+(s.KamerNummer).ToString());
listView1.Items.Add(la);
ListViewItem lb = new ListViewItem("Type kamer: "+(s.TypeKamer).ToString());
listView1.Items.Add(lb);
ListViewItem lc = new ListViewItem("Plekken: "+(s.AantalBedden).ToString());
listView1.Items.Add(lc);
listView1.Height = (listView1.Items.Count * 19);
tableLayoutPanel1.Controls.Add(listView1, x, y);
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
}
counter2++;
}
}
}
Related
I'm using GemBox.Presentation and I'm creating a large table in my PPTX file. Similar to this example, e.g.:
PresentationDocument presentation = new PresentationDocument();
Slide slide = presentation.Slides.AddNew(SlideLayoutType.Custom);
int rowCount = 100;
int columnCount = 4;
int columnWidth = 5;
Table table = slide.Content.AddTable(1, 1, columnCount * columnWidth, 0, LengthUnit.Centimeter);
for (int i = 0; i < columnCount; i++)
table.Columns.AddNew(Length.From(5, LengthUnit.Centimeter));
for (int r = 0; r < rowCount; r++)
{
TableRow row = table.Rows.AddNew(0);
for (int c = 0; c < columnCount; c++)
{
TableCell cell = row.Cells.AddNew();
TextParagraph paragraph = cell.Text.AddParagraph();
TextRun run = paragraph.AddRun(string.Format("Cell {0}-{1}", r + 1, c + 1));
}
}
presentation.Save("output.pptx");
As expected, the table doesn't fit on the slide:
So I need to split this table into multiple tables or multiple slides so that each table fits on its slide and all rows are visible.
How can I do that?
How can I find if the new TableRow will exceed the Slide height?
If you have dynamic row heights (for instance, some cells may contain multiple lines of text), then you'll need to paginate the content.
For example, see the following:
table.Frame.FormatDrawing(new PaginatorOptions() { UpdateTableRowHeights = true });
DrawingLayout tableLayout = table.Frame.Layout;
double maxHeight = presentation.SlideSize.Height - tableLayout.Top;
double currentHeight = 0;
TableRowCollection sourceRows = table.Rows;
TableRowCollection newRows = null;
int currentRowIndex = 0;
// Split the main table into multiple new tables based on the row heights.
while (currentRowIndex < sourceRows.Count)
{
currentHeight += sourceRows[currentRowIndex].Height;
// Create new slide with new table.
if (currentHeight > maxHeight)
{
currentHeight = sourceRows[currentRowIndex].Height;
Slide newSlide = presentation.Slides.AddNew(SlideLayoutType.Blank);
Table newTable = newSlide.Content.AddTable(tableLayout.Left, tableLayout.Top, tableLayout.Width, 0);
foreach (var column in table.Columns)
newTable.Columns.AddClone(column);
newRows = newTable.Rows;
}
// Move row from the main table to a new table.
if (newRows != null)
{
newRows.AddClone(sourceRows[currentRowIndex]);
sourceRows.RemoveAt(currentRowIndex);
}
else
{
++currentRowIndex;
}
}
presentation.Save("output.pptx");
If you have constant row heights, like shown in your screenshot, then you can simplify this.
For example, like the following:
int rowsPerSlide = 16;
TableRowCollection rows = table.Rows;
DrawingLayout layout = table.Frame.Layout;
for (int t = 1, tablesCount = (int)Math.Ceiling(rows.Count / (double)rowsPerSlide); t < tablesCount; t++)
{
Slide newSlide = presentation.Slides.AddNew(SlideLayoutType.Blank);
Table newTable = newSlide.Content.AddTable(layout.Left, layout.Top, layout.Width, 0);
foreach (var column in table.Columns)
newTable.Columns.AddClone(column);
for (int r = rowsPerSlide, rowsCount = Math.Min(rowsPerSlide * 2, rows.Count); r < rowsCount; r++)
{
newTable.Rows.AddClone(rows[rowsPerSlide]);
rows.RemoveAt(rowsPerSlide);
}
}
presentation.Save("output.pptx");
I created a CheckedListBox of about 12 Items. I want to dynamically create Textboxes to display and accept an input value from the user on the form each time an Item is selected. The Textboxes value is to be associated with the Selected Items Values for storage into some Sql database table when a Button is finally selected.
What I have been able to do so far is to have a single Textbox displayed even when I selected other items from the list box. Below is my Code
private void checkedList_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (e.NewValue == CheckState.Checked)
{
int n = 6;
selectedList.Items.Add(checkedList.SelectedItem.ToString());
for (int x=0; x < checkedList.SelectedItems.Count; x++)
{
TextBox[] txtBoxes = new TextBox[n];
for (int i = 0; i < n; i++)
{
txtBoxes[i] = new TextBox();
}
for (int i = 0; i < n; i++)
{
this.Controls.Add(txtBoxes[i]);
txtBoxes[i].Location = new Point(450, 100);
txtBoxes[i].Size = new System.Drawing.Size(25, 20);
txtBoxes[i].Validating += new CancelEventHandler(txt_Validating);
}
}
}
else
{
selectedList.Items.Remove(checkedList.SelectedItem.ToString());
}
}
private void InitializeMyListBox()
{
for (int x = 0; x < selectedList.Items.Count; x++)
{
selectedList.SetSelected(x, true);
}
// Force the ListBox to scroll back to the top of the list.
selectedList.TopIndex = 0;
}
What did I do wrong?
Can you please help with this.
You have set same location to all TextBoxes.
Try to set something like this:
txtBoxes[i].Location = new Point(450 + i*20, 100);
I want dynamic allocation datagridview in tablelayout.
For example, I choose number of grids, (2, 4, 9, 16...)
next, create this number of datagridview controls and place them in tablelayout.
Example:
So, how can I allocate dynamically allocate a number of Datagridview using one tablelayout
i created new Form (Form1), added new TableLayoutPanel with name t and added this code for form contructor:
public Form1()
{
InitializeComponent();
int row = 1; // number of rows
int col = 2; // number of columns (change them to see effect)
var grids = new DataGridView[row,col];
// create rows and set their height
t.RowCount = row;
t.RowStyles.Clear();
for (int r = 0; r < row; r++)
{
var style = new RowStyle();
style.SizeType = SizeType.Percent;
style.Height =(float)(1.0/row);
t.RowStyles.Add(style);
}
// create columns and set their width
t.ColumnCount = col;
t.ColumnStyles.Clear();
for (int c = 0; c < col; c++)
{
var style = new ColumnStyle();
style.SizeType = SizeType.Percent;
style.Width = (float)(1.0 / col);
t.ColumnStyles.Add(style);
}
// dynamically add grid in necessary place in layout
for(int r = 0; r<row; r++)
for (int c = 0; c < col; c++)
{
grids[r,c] = new DataGridView()
{
Dock = DockStyle.Fill,
};
t.Controls.Add(grids[r, c], c, r);
}
}
Hello everyone I need some help with the positioning of an array of buttons.I want to make this function so it scans the name of the previous button and it names the next one +1,afterwards I want to position these buttons on the screen having a certain space between them and them being positioned in the center of the screen.I have tried many times to modify my method but I don't know how to get this method to work.
This is how my method looks like.
UPDATED
PS.Reference not set to an instance of an object Q.Q
public Button[] ButtonCreator(byte numOfBtnsNeeded,Form1 form)
{
Button[] mybtns = new Button[numOfBtnsNeeded];
foreach (Button b in mybtns)
{
for (int i = 0; i < mybtns.Length; i++)
{
mybtns[i].Name = i.ToString();
mybtns[i].Parent = form;
mybtns[i].Height = 50;
mybtns[i].Width = 50;
for (int k = i + 1; k < mybtns.Length; k++)
{
mybtns[i].Location = new Point(190, 80);
mybtns[k].Location = Point.Add(new Point(mybtns[i].Location.X + 10,mybtns[i].Location.Y + 10),new Size(mybtns[i].Size.Width,mybtns[i].Size.Height));
}
}
}
foreach (Button b in mybtns)
{
b.Show();
}
return mybtns;
}
Play with this example...
public partial class Form1 : Form
{
private List<List<Button>> grid = new List<List<Button>>();
public Form1()
{
InitializeComponent();
byte numRows = 5;
byte numCols = 5;
for (byte i = 0; i < numRows; i++)
{
grid.Add(ButtonRowCreator(numCols, 25, (i+1) * 50));
}
}
public List<Button> ButtonRowCreator(byte numOfBtnsNeeded, int x, int y)
{
List<Button> btns = new List<Button>();
for (int i = 0; i < numOfBtnsNeeded; i++)
{
Button btn = new Button();
btn.Size = new Size(50, 50);
btn.Location = new Point(x + (i * btn.Width), y);
btns.Add(btn);
this.Controls.Add(btn);
btn.Click += new EventHandler(btn_Click);
}
return btns;
}
void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
btn.Text = "X";
int curRow = -1, curCol = -1;
for(int i = 0; i < grid.Count; i++)
{
int index = grid[i].IndexOf(btn);
if (index != -1)
{
curRow = i;
curCol = index;
Console.WriteLine("curRow = " + curRow.ToString() + ", curCol = " + curCol.ToString());
}
}
// ... now you can use "curRow", "curCol" and "grid" to do something ...
// reset all BackColors:
foreach (List<Button> row in grid)
{
foreach (Button col in row)
{
col.BackColor = Button.DefaultBackColor;
}
}
// the below should give you some examples for the
// syntax necessary to access buttons in the grid
// highlight current row:
foreach (Button col in grid[curRow])
{
col.BackColor = Color.Yellow;
}
// highlight current col:
for (int i = 0; i < grid.Count; i++)
{
grid[i][curCol].BackColor = Color.Yellow;
}
}
}
You cannot change a foreach variable reference (ie b). If you want to initialize an array you should use for loop:
for(int i = 0; i < numOfBtnsNeeded; i++)
{
var button = mybtns[i] = new Button();
//Here you can modify the reference of button.
}
Also, mybtns will be full of nulls since Button is a reference type which means it's default value is a null.
you want something like:
public Button[] ButtonCreator(byte numOfBtnsNeeded)
{
Button[] mybtns = new Button[numOfBtnsNeeded];
for (int i = 0; i < mybtns.Length; i++)
{
mybtns[i] = new Button();
mybtns[i].Name = (i + 1).ToString();
}
return mybtns;
}
I'm not sure why you're using a byte over an int, but it works either way.
Essentially, when you create the array, you're not creating the objects within the array. And you cannot modify the thing you are looping over within a foreach loop, so you need a for loop.
I'm trying to add very large number of columns into datagridview and I faced a challenging problem. When column count becomes too large the code below adds columns very slowly. This depends upon size value - when it less than 10000 I get more or less good result(2-4 seconds to add this number of columns), but when size grows up to 15000 or more the time of adding is not proportional at all, for 30000 of columns it can reach 2 minutes instead of 20-30 seconds as I expect. So my question is it possible to optimize this procedure somehow?
datagridview.SuspendLayout();
int size = 10000;
var columns = new DataGridViewColumn[size];
for (int i = 0; i < size; i++)
{
columns[i] = new DataGridViewTextBoxColumn();
columns[i].Name = "col" + i;
columns[i].HeaderText = "col" + i;
columns[i].FillWeight = 0.00001f;
}
datagridview.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
Array.ForEach(columns, item => datagridview.Columns.Add(item));
datagridview.ResumeLayout();
And this is what I've done:
int visibleColumns = 20;
string[] headers;
DataGridViewColumn[] columns;
HScrollBar hbar = new HScrollBar();
public Constructor(){
...
int sizeDezired = 15000;
int size = Math.Min(sizeDezired, visibleColumns);
columns = new DataGridViewColumn[size];
headers = new string[sizeDezired];
for (int i = 0; i < size; i++)
{
columns[i] = new DataGridViewTextBoxColumn();
columns[i].Name = "col" + i;
columns[i].HeaderText = "col" + i;
columns[i].FillWeight = 0.00001f;
}
for (int i = 0; i < sizeDezired;i++ )
{
headers[i] = "col" + i;
}
if (sizeDezired > size)
{
hbar.Maximum = sizeDezired - size;
hbar.Minimum = 0;
hbar.Value = 0;
}
hbar.Scroll += hbar_Scroll;
...
}
void hbar_Scroll(object sender, ScrollEventArgs e)
{
for (int i = 0; i < datagridview.ColumnCount; i++)
{
datagridview.Columns[i].HeaderText = headers[i + e.NewValue];
}
}
I added this code:
int visibleColumns = 20;// columns that are in data grid view
string[] headers;// headers for all desired columns
DataGridViewColumn[] columns;
HScrollBar hbar = new HScrollBar();
public Constructor(){
...
int sizeDesired = 15000;
int size = Math.Min(sizeDesired, visibleColumns);
columns = new DataGridViewColumn[size];
headers = new string[sizeDesired];
for (int i = 0; i < size; i++)
{
columns[i] = new DataGridViewTextBoxColumn();
columns[i].Name = "col" + i;
columns[i].HeaderText = "col" + i;
columns[i].FillWeight = 0.00001f;
}
for (int i = 0; i < sizeDesired;i++ )
{
headers[i] = "col" + i;
}
if (sizeDesired > size)
{
hbar.Maximum = sizeDesired - size;
hbar.Minimum = 0;
hbar.Value = 0;
}
hbar.Scroll += hbar_Scroll;
...
}
void hbar_Scroll(object sender, ScrollEventArgs e)
{
for (int i = 0; i < datagridview.ColumnCount; i++)
{
datagridview.Columns[i].HeaderText = headers[i + e.NewValue];
}
}
Here horizontal scroll bar added to cycle through all invisible columns and shift column headers to visually "scroll" through all columns(15000 in this example) but in reality only 20 columns are present. This code does not use any databinding, only headers are changing so you need to modify hbar_Scroll handler to show relevant data in cells.
The technique you are looking for is called pagination. Look at the following reference
"Paging is a great way to limit the amount of data displayed to the
user at one time, but is also a very good way of stopping lots of data
being transmitted across the network, being held in memory or big
queries on databases... It solves many problems.
The most common solution is (just like on a Google search) is you get
shown a list of pages and you can navigate around pages either going
up / down a page at a time or clicking on a page number.
Another way is to make it seem like there is actually one big list but
page behind the scenes so the user feels like they are actually
viewing one big list. An example where you see this done is in TFS.
You can do this with a windows forms data grid (DataGridView).