Stepping through controls in a wrappanel - c#

I have a bunch of controls located in a wrappanel in a WPF app that are procedurally created. The first control is a label followed by a bunch of comboboxes and a checkbox. The user clicks a button and a new row of controls are added. This worked fine. Then I decided to make the label a bit more attractive by giving it a red circle as a background and the label was nested in a grid with the red circel behind the label that simply listed the row number. This worked fine. And I use to step through all the controls with this block:
foreach (Control item in WrapPanelItems.Children)
{
if (item.GetType() == typeof(CheckBox))
{
RowCounter++;
}
}
now suddenly this block of code fails with this error: 'Unable to cast object of type 'System.Windows.Controls.Grid' to type 'System.Windows.Controls.Control'.'
So I suspect the grid isnt a conventional item and the code fails. But how would I then iterate through the controls without the app crashing and still iterate through all the conventional controls ontop of it?
Here is the code for how I style and add the label.
Grid MyGrid= new Grid();
Ellipse myEllipse = new Ellipse();
SolidColorBrush mySolidColorBrush = new SolidColorBrush();
mySolidColorBrush.Color = Color.FromArgb(255, 107, 142, 35);
myEllipse.Fill = mySolidColorBrush;
myEllipse.Width = 20;
myEllipse.Height = 20;
MyGrid.Children.Add(myEllipse);
Label LabelCounter = new Label();
LabelCounter.Content = RowCount.ToString();
MyGrid.Children.Add(LabelCounter);
LabelCounter.VerticalAlignment = VerticalAlignment.Center;
LabelCounter.HorizontalAlignment = HorizontalAlignment.Center;
WrapPanelItems.Children.Add(MyGrid);
And also a second question. Suppose I want to change the text on the label... how would I get to the label if its nested in a grid? Can you just change the content directly when the FOR loop picks up the grid? Or should you then say all children of grid when the grid is identified in the FOR loop?
tx

Grid is not a System.Windows.Controls.Control so this line throws an exception:
foreach (Control item in WrapPanelItems.Children)
You can replace Control with UIElement to avoid this error.
According to MSDN:
public class Grid : System.Windows.Controls.Panel, System.Windows.Markup.IAddChild

Related

is it possible to add elements like panel to a listbox, listview or other list with .items value using c# and winforms?

is it possible to add elements like panel to a listbox, listview or other list with .items?
I want to create panels with other elements like labels, checkbox, buttons,.. on a panel.
The panel should then be in a list so that I can check it for example: checkbox (which is on the panel) and is active in the list is showing, the other elements should be hidden in the list.
If a panel is between 2 panels, it should move upwards so that there is no space in between. If I then only display the panels of the non-activated elements, the hidden ones should be displayed again and the displayed ones should be hidden.
I would like to control this display using button event,
show everything,
only activated and
only deactivated.
With another button I would like to be able to bring a panel to the top position if it was declared as a favorite. if the favorite is removed again it should go back to where it was before.
In addition, I would then like to create a search mask that only displays the elements that match the search string when entered.
The only way I found is with listbox1.Controls.Add(panel1); for it to appear.
Unfortunately it doesn't work with listbox1.Items. :(
So I don't have a selectedItem either....
Here is my code that I have so far:
private void Reload_Click(object sender, EventArgs e)
{
Panel panel1 = new Panel();
panel1.Size = new Size (250, 35);
panel1.BackColor = Color.Red;
panel1.ForeColor = Color.Green;
panelxy.Dock = DockStyle.Top;
Panel panel2 = new Panel();
panel2.Size = new Size(250, 35);
panel2.BackColor = Color.Blue;
panel2.ForeColor = Color.Green;
panel2.Dock = DockStyle.Top;
listBox1.Controls.Add(panel1);
listBox1.Controls.Add(panel2);
Button btn_1 = new Button();
btn_1 .Size = new Size(200, 30);
btn_1 .Location = new Point(5, 2);
btn_1 .ForeColor = Color.Blue;
btn_1 .BackColor = Color.Yellow;
btn_1 .Font = new Font("Sitka Text", 15F, (FontStyle)(FontStyle.Bold | FontStyle.Italic), GraphicsUnit.Point, (byte) 0);
btn_1 .Text = "testbutton";
panel1.Controls.Add(btn_1 );
}
And here a Picture to show that:
listbox_elements
I hope someone can help me here. :)
thanks and BR
Cusy
Super thank you!
I just found out that it is possible to realize the required with a TableLayoutPanel. :)
Since I already have about 7000 lines of code, I don't want to convert it to WPF. ;)
i think the Answer from "Jimi" with FlowLayoutPanel are also a Solution. :)
Thanks
BR Cusy

Resizing and Collapsing label in winforms

first time poster, sorry if something isn't as it should be.
I'm new to Winforms and am trying to build a simple application that will display multiple features of an item (like Size, Composition, etc.). Each Characteristic has a Name, can have a Descritpion, and some can have sub-characteristics (having also a name and sometimes a descritpion).
I want to display them one under the other, with the Name of the feature on a blue background that span the whole width of the container, with the description underneath. The name will be (or have) a button (or similar) that when clicked collapse or expand the description. This must be created at run time because I don't know how many feature an object has until the user generate it.
The issues I'm running in are that either I can't span the blue background the whole width of the container (if using a FlowLayoutPanel), or I have some issue with the Description text being not the right size (either it wraps but is too big, or it doesn't wrap and then I can't see the whole text).
Some things are fixed, mainly the number of main sections (like Size, Composition, Weather, etc.), so I can prepare the skeleton before runtime.
The closest i've been to making it work gives this. This issue here is that the height of the Panel which the description label is embded in is fixed, and if I put in in Autosize, the text don't show (probably because the label is in Fill dock style). Just as information, this is what it looks like when collapsed (this is indeed what I'm looking for)
I know some library exists with collapsible panels, but I'd rather try to make it work without external libraries. Thanks in advance for any help !
This is the code that produces the results in the screenshots :
Panel SizeDescrPanel = new Panel();
SizeDescrPanel.Dock = DockStyle.Top;
//SizeDescrPanel.AutoSize = true;
SizeDescrPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
SizeDescrPanel.BackColor = Color.Bisque;
SizePanel.Controls.Add(SizeDescrPanel);
Label SizeDescrLbl = new Label();
SizeDescrLbl.Text = Lorem;
SizeDescrLbl.AutoSize = false;
SizeDescrLbl.Dock = DockStyle.Fill;
SizeDescrLbl.BackColor = Color.BurlyWood;
SizeDescrPanel.Controls.Add(SizeDescrLbl);
/*using(Graphics g = CreateGraphics())
{
SizeF size = g.MeasureString(SizeDescrLbl.Text, SizeDescrLbl.Font, SizePanel.Width);
SizeDescrPanel.Height = (int) Math.Ceiling(size.Height);
}*/
Panel SizeNamePanel = new Panel();
SizeNamePanel.Dock = DockStyle.Top;
SizeNamePanel.BackColor = Color.Cyan;
SizeNamePanel.AutoSize = true;
SizePanel.Controls.Add(SizeNamePanel);
Button SizeNameBtn = new Button();
SizeNameBtn.Text = "<Size Name> ..." + SizeDescrLbl.Height;
SizeNameBtn.TextAlign = ContentAlignment.MiddleLeft;
SizeNameBtn.FlatStyle = FlatStyle.Flat;
SizeNameBtn.AutoSize = true;
SizeNamePanel.Controls.Add(SizeNameBtn);
SizeNameBtn.Click += delegate { HideShowPanel(SizeDescrPanel); };
It,s a test project, so later I'll put that in different methods. What isn't shown here :
I have a main panel set to Fill containing everything.
The text "SIZE" is a label set to Top
Under it is another Panel (SizePanel) that is set to Top and Autosize is at True. This is the Panel inside which I'm puttin my size name and my size description. If I had a subfeature, it would be included (ideally) inside descritpion with the same configuration (button expanding/collapsing the descritpion of the SubFeature)

Why do controls delete when copying controls from one panel to the next

I created a template panel to go by when my form loads that holds a record. When adding a new record I have a method that duplicates that template panel and then adds it to my list of panels for each record. Somehow controls are getting deleted from my template panel when I am duplicating it and I have no idea how this is happening. The portion of code doing this is listed below
Panel pn = new Panel()
{
Width = _PNTemp.Width,
Height = _PNTemp.Height,
Left = 0,
Top = 0,
BackColor = _PNTemp.BackColor,
ForeColor = _PNTemp.ForeColor,
AutoScroll = true,
Name = _PNTemp.Name,
Tag = _PrgPanels.Count.ToString()
};
MessageBox.Show(_PNTemp.Controls.Count.ToString());
foreach (Control c in _PNTemp.Controls)
{
pn.Controls.Add(c);
MessageBox.Show(_PNTemp.Controls.Count.ToString());
}
MessageBox.Show(_PNTemp.Controls.Count.ToString());
_PrgPanels.Add(pn);
I put the messagebox.show() in at 3 points to narrow down where it is happening. The first one shows the correct number of controls, the second and third shows a 1/2 the total amount of controls. why is this?
This is because each control can be added to only one parent control. All controls in your template panel are already a child of the template panel. When you try to add these controls to a new panel, the controls will get removed from the template panel.
As per the docs:
A Control can only be assigned to one Control.ControlCollection at a
time. If the Control is already a child of another control it is
removed from that control before it is added to another control.
Which means that you need to create new controls instead of adding those in the template.
An alternative approach is to create a method that returns the template panel. When you need the template panel, just call the method and a new panel will be created:
public static Panel CreateTemplatePanel() {
Panel pn = new Panel();
// set properties, add controls...
return pn;
}
A control can only be on one panel at once. I've added comments inline in your code to help explain whats happening.
Panel pn = new Panel()
{
Width = _PNTemp.Width,
Height = _PNTemp.Height,
Left = 0,
Top = 0,
BackColor = _PNTemp.BackColor,
ForeColor = _PNTemp.ForeColor,
AutoScroll = true,
Name = _PNTemp.Name,
Tag = _PrgPanels.Count.ToString()
};
MessageBox.Show(_PNTemp.Controls.Count.ToString());
//all the controls are still inside _PNTemp
foreach (Control c in _PNTemp.Controls)
{
pn.Controls.Add(c);
MessageBox.Show(_PNTemp.Controls.Count.ToString());
//Each time this runs you remove a control from _PNTemp to pn.
}
//All the controls moved from _PnTemp to pn
MessageBox.Show(_PNTemp.Controls.Count.ToString());
_PrgPanels.Add(pn);

How can I include icons in my ListBox?

I know that similar questions have already been asked here before, but they all lead to the same codeproject article that doesn't work. Does anybody know of a working ListBox with icons?
Will a ListView work for you? That is what I use. Much easier and you can make it look just like a ListBox. Also, plenty of documentation on MSDN to get started with.
How to: Display Icons for the Windows Forms ListView Control
The Windows Forms ListView control can display icons from three image
lists. The List, Details, and SmallIcon views display images from the
image list specified in the SmallImageList property. The LargeIcon
view displays images from the image list specified in the
LargeImageList property. A list view can also display an additional
set of icons, set in the StateImageList property, next to the large or
small icons. For more information about image lists, see ImageList
Component (Windows Forms) and How to: Add or Remove Images with the
Windows Forms ImageList Component.
Inserted from How to: Display Icons for the Windows Forms ListView Control
If you don't want to change ListBox to a ListView you can write a handler for DrawItemEvent. for example:
private void InitializeComponent()
{
...
this.listBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.listBox_DrawItem);
...
}
private void listBox_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index == -1)
return;
// Draw the background of the ListBox control for each item.
e.DrawBackground();
var rect = new Rectangle(e.Bounds.X+10, e.Bounds.Y+8, 12, 14);
//assuming the icon is already added to project resources
e.Graphics.DrawIconUnstretched(YourProject.Properties.Resources.YouIcon, rect);
e.Graphics.DrawString(((ListBox)sender).Items[e.Index].ToString(),
e.Font, Brushes.Black, new Rectangle(e.Bounds.X + 25, e.Bounds.Y + 10, e.Bounds.Width, e.Bounds.Height), StringFormat.GenericDefault);
// If the ListBox has focus, draw a focus rectangle around the selected item.
e.DrawFocusRectangle();
}
you can play around with the rectangle to set the location of the icon right
If you're stuck working in WinForms, then you'll have to owner-draw your items.
See the example for the DrawItem event.
A little different approach - don't use a list box.
Instead of using that control that bounds me to its limited set of properties and methods I am making a listbox of my own.
It's not as hard as it sounds:
int yPos = 0;
Panel myListBox = new Panel();
foreach (Object object in YourObjectList)
{
Panel line = new Panel();
line.Location = new Point(0, Ypos);
line.Size = new Size(myListBox.Width, 20);
line.MouseClick += new MouseEventHandler(line_MouseClick);
myListBox.Controls.Add(line);
// Add and arrange the controls you want in the line
yPos += line.Height;
}
Example for myListBox event handlers - selecting a line:
private void line_MouseClick(object sender, MouseEventArgs)
{
foreach (Control control in myListBox.Controls)
if (control is Panel)
if (control == sender)
control.BackColor = Color.DarkBlue;
else
control.BackColor = Color.Transparent;
}
The code samples above were not tested but the described method was used and found very convenient and simple.

Add and remove the UserControl dynamically

I have UserControl that holds Infragistics Graph control. On the TreeView sub node's right click, I have context menu as "Create Graph". This will create the new graph. This is about what i going to do.
I have confusion about what layout to use. Whether FlowLayoutPanel or TableLayoutPanel or anything else. If only one graph is add --> graph has to occupy the full form. If two graph are added --> two graph's has to split the space and so on.This is only in the format of one after another. ie First graph at top, second is below to first ..so on.
If UserControl is manually changed it should not affect the size where we displaying.
This is the WinForm. Currently i using FlowLayoutPanel, i creating panel with the constant size and added the UserControl with DockStyle.Fill. Then i added the Panel to the FlowLayoutPanel.
GraphUserControl usr = new GraphUserControl();
usr.Dock = DockStyle.Fill;
Panel pnl = new Panel();
pnl.Controls.Add(usr);
flowLayoutpnl.Controls.Add(pnl);
What is the best approach to do this?.
A TableLayoutPanel is probably your best choice, as the row heights can be set to a percentage value.
private void AddControl(Control ctl)
{
tableLayoutPnl.RowCount += 1;
tableLayoutPnl.RowStyles.Add(
new RowStyle(SizeType.Percent, 100F / tableLayoutPnl.RowCount));
ctl.Dock = DockStyle.Fill;
tableLayoutPnl.Controls.Add(ctl, 0, tableLayoutPnl.RowCount - 1);
foreach (RowStyle rs in tableLayoutPnl.RowStyles)
{
rs.Height = 100F / tableLayoutPnl.RowCount;
}
}
You can then call this as follows:
GraphUserControl usr = new GraphUserControl();
AddControl(usr);

Categories