Team.
I have a Problem with my Tablelayoutpanel. The Tablelayoutpanel is located in the Main-Form and filled with 5 Usercontrols (5 equal Controls, filled with other texts).
Every Usercontrol contains a button. If I click on that button in the UC, 10 other Usercontrols should be added AFTER the clicked Usercontrol.
My Code so far (In the Button-Click Method):
private void bt_Öffnen_Click(object sender, EventArgs e)
{
var ziele = getZielStatement();
foreach (var z in ziele.Where(z => z.Hauptziele.PerspektivenID == gl_PerspektiveID)) // Für jedes Ziel in der jeweiligen Perspektive
{
Uc_Ziele uc_ziel = new Uc_Ziele();
uc_ziel.gl_Unterziel = z;
this.Parent.Controls.Add(uc_ziel);
}
}
The problem is, that the Controls are added at the end of TableLayoutpanel. They should be added after the clicked Usercontrol.
I cant do it without help. Hope you get what i want.
Greets, Daniel
After you've added the control use the SetChildIndex method to move it to its correct position.
Check out this post for further info
How to add rows into middle of a TableLayoutPanel
Related
I'm trying to dynamically create a list of panels containing a label and a textbox and put those panels into a bigger panel.
My problem is that only the first child panel gets added to the parent panel.
I've tried adding the panels directly into controls as well as this addrange method.
Also I'm aware of another question with this problem but it is six years old and the solution did not work for me.
the Panel pnl is being populated by a Panel containing a label and textbox that is already on the form. that panel is then deleted from the controls and pnl remains
EDIT FOR CLARIFICATION:
The code will loop multiple times but when it reaches panel1.Controls.AddRange(controls); the total count of panel1.controls is 1 regardless of the length of array controls
Panel pnl;
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Control[] controls = new Control[8];
for (int i = 0; i < int.Parse(ddlPlayers.SelectedItem.ToString()); i++)
{
pnl.Name = "pnl " + i.ToString();
if (i!= 0)
pnl.Location = new Point(pnl.Location.X, controls[i - 1].Location.Y + Height);
pnl.Show();
controls[i] = pnl;
}
panel1.Controls.AddRange(controls);
}
The problem was that I wasn't declaring a new panel, I was just using the same control. I thought by putting the controls into an array it meant they would be different but I was wrong.
check this line ---> int.Parse(ddlPlayers.SelectedItem.ToString())
I am new to C#. I am using windows forms and I have Form1 which contains 2 buttons ( one to create user control at run time and the other creates buttons on user control at run time).
This code creates user control and FlowLayoutPanel (to organize button position) if you click add_UserControl button. And then it creates buttons on FlowLayoutPanel if you click Add_Buttons button and it is all done at run time.
Now in Form1 let's say I created user control and FlowLayoutPanel and then created 5 buttons , how can I save the properties/details of this user control with its FlowLayoutPanel and 5 buttons in SQL database so I can use them later when I run the program? I have been thinking about an idea and I reached the internet but no luck.
Any idea? Please help me. Thank you
public partial class Form1 : Form
{
FlowLayoutPanel FLP = new FlowLayoutPanel();
UserControl uc = new UserControl();
private void add_UserControl_Click(object sender, EventArgs e)
{
uc.Height = 700;
uc.Width = 900;
uc.BackColor = Color.Black;
Controls.Add(uc); //add UserControl on Form1
FLP.Height = 600;
FLP.Width = 800;
FLP.BackColor = Color.DimGray;
uc.Controls.Add(FLP); // add FlowLayoutPanel to UserControl
}
private void Add_Buttons_Click(object sender, EventArgs e)
{
//####### add buttons to FlowLayoutPanel ############
Button dynamicButton = new Button();
dynamicButton.Height = 50;
dynamicButton.Width = 200;
dynamicButton.BackColor = Color.Green;
dynamicButton.ForeColor = Color.Blue;
dynamicButton.Text = "";
FLP.Controls.Add(dynamicButton);
}
}
OK, First you need to create a class that will represent one of the buttons with the properties you need.
class MyButton
{
public string ButtonText {get;set;}
}
Everytime you click and create a button, you actually create an object of this class and add it to a collection or list. Then you would have some other code watching over the collection, and every time it gets a new entry, it creates a new button and sets its Button text to the text property. when a member of list is gone, it removes the button.
If you need more properties to be remembered (color, size, font, ...) you add them to the class as well. If you need for other controls, as well, .... you can always create common parent controls.
Simple.
If you want to be able to reload it, you could define the MyButton class as serializable and store it in xml file, and upon build, reload it.
You should watch into WPF and it's MVVM pattern. It's pretty much similar to it. Also have a look into command pattern, usefull pattern when it commes to this.
You can remember the FlowLayoutsPanels in one SQL table and in another table you could save the buttons which belong to these FlowLayoutPanels.
On Form Load or Application Load, you could check if there are already FlowLayoutPanels and correspending Buttons do exist in the SQL db and if yes then create them, else do nothing.
Hello I'm thinking of creating a tabcontrol which the tabpages will be filtered by the clicks in the menustrip.
For ex.
My menustrip is in form 1
and my tabcontrol is in form 2
My tabcontrol consist of 7 tabs and I want only 1 tab will be shown at a time.
for example If I click the name in the menustrip it will open/show a new form and the tabcontrol will only show the names tab.
I wonder if its possible because making diff forms for each list seems to be very long.
thanks for reading this.
Problem is, the TabPage control has no Visible property (well, it has, but it does nothing). So you can't hide and show tabs at will. You'll have to remove the tabs that should not be visible.
You could make a form (named TabbedForm) with code like this:
private readonly int _index;
public TabbedForm(int index)
{
this._index = index;
InitializeComponent();
}
private void form_Load(object sender, EventArgs e)
{
for (int index = this.tabControl1.TabPages.Count - 1; index >= 0; index--)
{
if (index != this._index)
this.tabControl1.TabPages.Remove(this.tabControl1.TabPages[index]);
}
}
With each menu button (Clicked event) in your main form you can open a TabbedForm with a different index.
Yes, this will work pretty fine. But I think, you must use the default tab view control for this and that must not create the problem either in you case too.
I'm trying to make a list of controls. For this, I used a flow layout panel and a custom item. After reading a XML file I populate the flow layout panel with my items. For a small number of items everything seams to be OK but for a number like 371 of items in the flow layout panel something get's wrong. At the bottom of the flow layout panel 95 items are missing, and seams to be overlapped. The space located for this items, i think, is still created. I attach a screen with the effect produced. The controls are created in an array and then I iterate that array to add the controls to the flow layout panel.
http://img510.imageshack.us/img510/3201/screen2011916213527199.jpg
Thank you.
LE:
public delegate void AddHistoryItemDelegate(Control itm);
public void AddHistoryItem(Control itm)
{
if (InvokeRequired)
{
Invoke(new AddHistoryItemDelegate(AddHistoryItem), new object[] { itm });
}
else
{
flowLayoutPanel1.Controls.Add(itm);
}
}
foreach (Control c in histroryItems)
{
controls++;
backgroundWorkerLoadHistory.ReportProgress(controls);
//flowLayoutPanel1.Controls.Add(c);
AddHistoryItem(c);
}
The delegate is there because all this is taking place in a separate thread. histroryItems is a List of controls.
LE: If it's counts, i observed that, if I remove an item from the list, after the list loads, it get's arranged. Trying a little hack to see if adding and removing a control at the end of the thread, does not have any effect.
You could try this:
this.flowLayoutPanel1.SuspendLayout();
before adding controls and:
this.flowLayoutPanel1.ResumeLayout();
after adding controls. Maybe the following should be performed consecutively:
this.flowLayoutPanel1.PerformLayout();
and/or:
this.flowLayoutPanel1.Refresh();
I found that I had to do this:
private void flpChoices_Scroll(object sender, ScrollEventArgs e)
{
Control c=flpChoices.GetChildAtPoint(new Point(10, 10), GetChildAtPointSkip.None);
if (c == null) flpChoices.PerformLayout();
}
Where flpChoices is my FlowLayout Panel. Now I don't think the scroll event is triggered on mouse wheel movement, so I don't know what to do about that.
EDIT: There is a hidden(not in the property window) even for scroll wheel:
void flpChoices_MouseWheel(object sender, MouseEventArgs e)
{
Control c=flpChoices.GetChildAtPoint(new Point(10, 10), GetChildAtPointSkip.None);
if (c == null) flpChoices.PerformLayout();
}
In my C# winforms app, I have a datagrid. When the datagrid reloads, I want to set the scrollbar back to where the user had it set. How can I do this?
EDIT: I'm using the old winforms DataGrid control, not the newer DataGridView
You don't actually interact directly with the scrollbar, rather you set the FirstDisplayedScrollingRowIndex. So before it reloads, capture that index, once it's reloaded, reset it to that index.
EDIT: Good point in the comment. If you're using a DataGridView then this will work. If you're using the old DataGrid then the easiest way to do that is to inherit from it. See here: Linkage
The DataGrid has a protected GridVScrolled method that can be used to scroll the grid to a specific row. To use it, derive a new grid from the DataGrid and add a ScrollToRow method.
C# code
public void ScrollToRow(int theRow)
{
//
// Expose the protected GridVScrolled method allowing you
// to programmatically scroll the grid to a particular row.
//
if (DataSource != null)
{
GridVScrolled(this, new ScrollEventArgs(ScrollEventType.LargeIncrement, theRow));
}
}
Yep, definitely FirstDisplayedScrollingRowIndex. You'll need to capture this value after some user interaction, and then after the grid reloads you'll want to set it back to the old value.
For instance, if the reload is triggered by the click of a button, then in the button click handler, you might want to have as your first line a command that places this value into a variable:
// Get current user scroll position
int scrollPosition = myGridView.FirstDisplayedScrollingRowIndex;
// Do some work
...
// Rebind the grid and reset scrolling
myGridView.DataBind;
myGridView.FirstDisplayedScrollingRowIndex = scrollPosition;
Store your vertical and horizontal scroll values into some variable and reset them.
int v= dataGridView1.VerticalScrollingOffset ;
int h= dataGridView1.HorizontalScrollingOffset ;
//...reload
dataGridView1.VerticalScrollingOffset = v;
dataGridView1.HorizontalScrollingOffset =h;
you can save scroll position with next code
int Scroll;
void DataGridView1Scroll(object sender, ScrollEventArgs e)
{
Scroll = dataGridView1.VerticalScrollingOffset;
}
and you can set scroll of dgv to same position after refresing, load dgv... with next code:
PropertyInfo verticalOffset = dataGridView1.GetType().GetProperty("VerticalOffset", BindingFlags.NonPublic |
BindingFlags.Instance);
verticalOffset.SetValue(this.dataGridView1, Scroll, null);
Just posted the answer on the link given by BFree
The DataGrid has a protected GridVScrolled method that can be used to scroll the grid to a specific row. To use it, derive a new grid from the DataGrid and add a ScrollToRow method.
C# code
public void ScrollToRow(int theRow)
{
//
// Expose the protected GridVScrolled method allowing you
// to programmatically scroll the grid to a particular row.
//
if (DataSource != null)
{
GridVScrolled(this, new ScrollEventArgs(ScrollEventType.LargeIncrement, theRow));
}
}
VB.NET code
Public Sub ScrollToRow(ByVal theRow As Integer)
'
' Expose the protected GridVScrolled method allowing you
' to programmatically scroll the grid to a particular row.
'
On Error Resume Next
If Not DataSource Is Nothing Then
GridVScrolled(Me, New ScrollEventArgs(ScrollEventType.LargeIncrement, theRow))
End If
End Sub
I used the answer by #BFree, but also needed to capture the first visible row in the DataGrid:
int indexOfTopMostRow = HitTest(dataGrid.RowHeaderWidth + 10,
dataGrid.PreferredRowHeight + 10).Row;
Even though this is an old question, Many of the solutions above did not work for me. What worked ultimately was:
if(gridEmployees.FirstDisplayedScrollingRowIndex != -1) gridEmployees.FirstDisplayedScrollingRowIndex = 0;