So I am trying to add a UserControl to a windows form, however I want to add it in a variable location when a button is clicked.
So I have a groupbox in one location and I want the first one to go to the extreme left directly under the groupbox, I then want the next one to be in a position relative to the first, and all subsequent ones to be in a position in relation to the one before. However with restricted space a new line of these controls would have to be eventually created.
I am not sure if this is possible, or how I would do it. Currently I only know how to define a specific point for the control to be created at.
The only part of the code that really matters:
private void addpilot_Click(object sender, EventArgs e)
{
PilotControl newPilot = new PilotControl();
newPilot.Location = new Point();
this.Controls.Add (newPilot);
}
I think that this behavior could be similar to a WrapPanel. If it is not, you may try to solve this using another Panel, or also, implementing your own panel to create an specific location behavior.
Try seen Panels Overview in the MSDN.
Look into docking and flow controls.
Related
I am currently working on a Editor, which lets the user design his own WinForm overlay, at least to a certain point.
Therefore I want the user to decide, which AnchorStyles the current selected Control should have. I would like it to be handled by checkboxes. Here's how I had it in mind:
As you can see, the user has currently selected a dynamically added Panel, called Grid. Handled by the CheckBoxes to the right, he should now be able to set the selected Controls AnchorStyles.
Here's my problem: I can't seem to find a usable solution, to dynamically add a specific AnchorStyle to the already existing ones, or the opposite, remove the AnchorStyle, but keep the other ones as they are.
I was trying to get it to work with...
SelectedControl.Anchor += AnchorStyles.Top;
which doesen't work at all. So i thought of this...
SelectedControl.Anchor = SelectedControl.Anchor | AnchorStyles.Top
which I imagine could work, but I haven't even tested it, since I wouldn't know how to remove ones unchecked AnchorStyle.
Building a gigantic if(){} else if(){}... doesen't seem to be a good Idea :)
I'm open for any ideas / solutions.
Thanks in advance!
Assuming you have four check box controls named top, bottom, left and right, you can handle CheckedChange event of them using a single method and set the anchor of the desired control based on the checked value of the controls. For example:
private void checkBox_CheckedChanged(object sender, EventArgs e)
{
var values = new[] { top.Checked, bottom.Checked, left.Checked, right.Checked };
byte[] data = new byte[1];
new BitArray(values).CopyTo(data, 0);
selectedControl.Anchor = (AnchorStyles)data[0];
}
Note: AnchorStyles is a flag enum having top=1, bottom=2, left=4 and right=8. Using above code I've mixed those flags to create the AnchorStyles and have assigned to the Anchor property of control.
So I have an application that uses a single master form with a menu along the left-side of the form.
On the right-side I have a panel that acts as a placeholder for any UserControl I have created.
Each time a user clicks on a menu item, the related UserControl will display using code like this:
//Display UserControl first
ucMyUserControl uc = new ucMyUserControl ();
uc.Dock = DockStyle.Fill;
pnlContainer.Controls.Add(uc);
Is there a better way than to just copy and paste this for each button or whenever I want to display a UserControl. Should I be creating a function to call each time and just passing the name of the UserControl I want to use?
Maybe I've got it all wrong in the first place with the way I'm using it - I'm new to this concept and just trying things out.
Sure, don't repeat yourself. Write DRY code with a helper method. It could look like this:
public void ShowPage(UserControl uc) {
while (pnlContainer.Controls.Count > 0) pnlContainer.Controls[0].Dispose();
uc.Dock = DockStyle.Fill;
pnlContainer.Controls.Add(uc);
}
And now you simply call ShowPage(new ucMyUserControl());
Note that the quirky looking while-loop is important, you don't just want to use the Controls.Remove() method. Disposing controls that you remove is very important, if you don't then they'll live forever and ultimately crash your program.
So here's my Question, I'm new to C#(teaching my self at that) Here's the thing, I'm working on a basic sim game, nothing to complex but I've got the design and basic functions done.
However In order to implement it, I'm currently using multiple Forms(Visual Studio 2013)
I have my "main" form which has the "action" buttons to it
So when i want to go to a user Profile page I have
Btn_profileview Click(object sender, EventArgs e){
Form profile = new Form();
profile.Show();
}
The User would then implement the changes(for instance change name) which is written to a text file, for use in other areas of the program.
However It opens a new windows, I've tried modal and nonmodal windows and while the benefit of Modal so they have to actual close the window solves the issue, i'd rather have it just overwrite the preexisting Form, and then on close go back to the "main" screen without actually using multiple windows.
Now I was told UserControl and/or Panel would solve the issue, but it would cause a complete redesign moving from the multiple forms to the multiple panel screens and figuring out how to get those to work(Visible and Invisible), i'm assuming it wouldn't be extremely difficult something along the lines of Panel"name".show(); and panel"name".close();
But would it be possible to actually add a line of code to the pre-existing code(so as not to cause a complete reesign) or are Panels and UserControl the only real way to implement within 1 continuous windows?
paqogomez is right: There are many ways to do it.
Here is one that combines a lot of the pros:
You create an invisible Tab on your window with as many pages as you need. Place a Panel on each tab and create all your controls on of them. This does not mean that you have to do it all over - you can move and drop the controls you already have without much hassle. Of course you need to turn off docking and maybe anchors, but other than that this is a simple process.
If you have controls on the 2nd form with the same name, these names should be changed to something unique though. I hope all Controls have proper names already, but especially Labels get neglected, at least here.. (With a little luck you can even use cut and paste to get Controls from another form to panel2!)
The big pro of this trick is that you can do all work in the designer of the same form. The Tab control serves only as a container where you keep your panels without adding to the UI and without giving the user control of what is shown.
Next you create one Panel variable in your main form:
Panel currentPanel;
On Load you assign the first 'real' Panel to it like this:
currentPanel = panel1;
this.Controls.Add(currentPanel);
Later, each time you want to switch, you re-assign the panels you need like this:
this.Controls.Remove(currentPanel);
currentPanel = panel2; // or whichever panel you want to show..
this.Controls.Add(currentPanel );
If your real panels are docked to fill the tabpage, as they should, the currentPanel will fill the form. You still have access to each panel and to each control by their names at any time but you see no overhead of tabs and your form never changes, except for the full content.
Here is my form
If I click on "Add" on the first panel I want to create "Strategy1_2" just below the first and shift all others panels down.
If I click again I want to create Strategy1_3 (...)
I know how to create a button but not how to duplicate a entire panel.
Here is my code for a button is it far from this procedure ?
private void addstrat1_i_Click(object sender, EventArgs e)
{
panel3strat.Width += 200;
Button addstrat1_2 = new Button();
addstrat3_2.Size = new Size(210, 41);
addstrat1_2.Location = new Point(31,89);
addstrat1_2.Visible = true;
panel1strat.Controls.Add(addstrat3_2);
}
The best way would be that you create a UserControl for your strategy panel. You can then insert the UserControls to a FlowLayoutPanel. This will resolve your issue with placing controls exactly and to create a copy of some panels.
Be aware that you can run out of resources (e.g. windows handles) when adding to much controls on your form. This can be solved by only showing a certain amount of controls and shifting the data through this "fixed" controls while scrolling.
I recommend having two methods: CreatePanelBlock() that will issue a UserControl that you'll add to your container, and BindPanelWithData(...) that will setup the dependencies.
Remember, you may make your panel as a custom control.
Are there any other methods of bringing a control to the front other than control.BringToFront()?
I have series of labels on a user control and when I try to bring one of them to front it is not working. I have even looped through all the controls and sent them all the back except for the one I am interested in and it doesn't change a thing.
Here is the method where a label is added to the user control
private void AddUserLabel()
{
var field = new UserLabel();
userContainer.Controls.Add(field);
SendLabelsToBack(); // Send All labels to back
userContainer.Controls[field.FieldName].BringToFront();
}
Here is the method that sends all of them to the back.
private void SendLabelsToBack()
{
foreach (var label in userContainer.Controls);
label.SendToBack();
}
Yeah, there's another way. The Controls.SetChildIndex() also changes Z-order. The one with index 0 is the one on top. Doesn't buy you anything though, BringToFront() uses this method.
Your SendLabelsToBack() method as given cannot work, it will also send the label to added to the back. But your next statement fixes that again.
Okay, that doesn't work, which means the BringToFront() method doesn't get executed. Look in the Output window for a "first chance exception" notification. As written, your SendLabelsToBack() will cause an exception if the user control contains any control other than a UserLabel. Also, set a breakpoint after the BringToFront() call and check the value of userContainer.Controls[0].Name when it breaks.
Controls' z-index is per-container.
If you call BringToFront on a control that is inside a container (such as a Panel), it will not bring the container to the front.
Therefore, the control will only go in front of other controls in that container.
To see what containers your controls are in, you can use the Document Outline pane in the View menu.
EDIT: Your userContainer control is probably behind a different control.
Have you tried Invalidate() after BringToFront()? BringToFront does not raise the Paint event
try this:
private void SendLabelsToBack()
{
foreach (var label in userContainer.Controls)
{
label.SendToBack();
label.Invalidate();
}
}
I think you just need to change your last line:
userContainer.Controls[field.FieldName].BringToFront();
to this:
userContainer.Controls[field.Name].BringToFront();
When you use a string as the indexer for the Controls collection, it goes by the Name property of the control (not the FieldName property).
Since you're just trying to bring the most recently-added control to the top, this would also work:
userContainer.Controls[userContainer.Controls.Count - 1].BringToFront();
From my experience looks like windows puts all controls belonging to one graphic container(pane, group box...etc) in a software collection. The collection is ordered by child index which is a property of every control in that container.
The trick is that children with the same index can and do exists. In this case windows will paint those children ordered relative to others but between them it will paint them in the reverse order they had been added to the container.
Long story short: for one container-you need to make sure controls have different indexes by changing ALL NOT just SOME of the indexes when you want to change the z-order. For example:
foreach (Control newControl in TopControl.Controls)
{
TopControl.Controls.SetChildIndex(newControl,indexlogic(newControl));
}
where indexLogic(newControl ) is your method of calculation of the index of particular control.