Basic Layout with WindowsForms - c#

How do I create a simple form that has a MenuStrip at the top and a TabControl filling all of the remaining space?
If I go with DockStyle.Top/DockStyke.Fill tabControl fills whole form regardless of MenuStrip:
public MainWindow()
{
initializeComponent();
}
private void initializeComponent()
{
MenuStrip mainMenu = new MenuStrip();
mainMenu.Dock = DockStyle.Top;
TabControl tabs = new TabControl();
tabs.Dock = DockStyle.Fill;
TabPage test = new TabPage("test");
tabs.Controls.Add(test);
Controls.Add(mainMenu);
Controls.Add(tabs);
}

You should change the z-order of mainMenu or tabs. For example you can call:
mainMenu.SendToBack();
//Or
//tabs.BringToFront();
After adding controls to the controls collection.

Another approach through designer, without writing code manually, so your changes will affect design time too
Use Document outline tab and arrange control's hierarchy with your requirements
View -> Other Windows -> Document outline or CTRL+ALT+T

Related

Parent form's control to be in front of child form (Winforms)

I have a program with a horizontal dropbox with 4 options to choose from in which "sub buttons" will appear when I click on one of these buttons:
Here is the interface:
And what I want to do is that when I click on one of the drop down menu options, I want a childform to spawn on the black area, using this:
private Form activeForm = null;
private void openChildForm(Form childForm)
{
if (activeForm != null)
activeForm.Close();
activeForm = childForm;
childForm.TopLevel = false;
childForm.FormBorderStyle = FormBorderStyle.None;
childForm.Dock = DockStyle.Fill;
MainInterfacePanel.Controls.Add(childForm);
MainInterfacePanel.Tag = childForm;
childForm.BringToFront();
childForm.Show();
}
However, when I do so, the childform does appear normally, but it covers the dropdown menu, preventing me to select other functions:
Here's how it looks like(the childform is still a blank form, thus the whiteness):
I tried solving this issue by using item.bringToFront() on the buttons, but it dosent seem to work.
Basically, I want the Parent Form to stay behind the childform, while having the buttons be infront of the childform, like an overlap. Is there a way to do so?
Also, when I remove the 'childForm.BringToFront()', for whatever reason it spawns behind the interface.
You should have to use Panel in which child form may appear. Simply add Panel from Toolbox and change its Dock property to top and place all your menu items in that Panel and also add new Panel i.e. MainPanel to display forms and than use following code to display form inside the Panel
SubForm objForm=new SubForm();
objForm.TopLevel = false;
MainPanel.Controls.Add(objForm);
objForm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
objForm.Dock = DockStyle.Fill;
objForm.Show();

Implementing an options dialog

in my application i want to implement an options dialog like you have in VisualStudios if you go to Tools->Options in the menubar. How can i do this? My first idea was to use pages and navigation but maybe there's an easier approach?
It's probably not the easiest way but I wrote this snippet that match your goal and it's a good exercise.
In an empty Windows Forms project add a ListBox (listBox1) and a Panel (panel1). Then create 2 UserControls (UserControl1 and UserControl2), these will be the content that is shown when you click the list.
In your Form1 class we create a ListItem class that will contain your menu options as such:
public partial class Form1 : Form
{
public class ListItem
{
public string Text { get; set; }
public UserControl Value { get; set; }
public ListItem(string text, UserControl value)
{
Text = text;
Value = value;
}
};
...
}
After that you add items to the ListBox right after InitializeComponent() in Form1:
public Form1()
{
InitializeComponent();
listBox1.DisplayMember = "Text";
listBox1.ValueMember = "Value";
listBox1.Items.Add(new ListItem("Item1", new UserControl1()));
listBox1.Items.Add(new ListItem("Item2", new UserControl2()));
}
This will make it so when you use listBox1.SelectedItem it will return an object that you can cast to a ListItem and access the associated UserControl.
To make use of this behaviour, go to designmode and double-click the ListBox, this'll add code for the SelectedIndexChanged event. We use this event to display the UserControl in the Panel panel1. This will clear any old Panel content and add a selected UserControl:
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
panel1.Controls.Clear();
UserControl control = (listBox1.SelectedItem as ListItem).Value;
if(control != null)
{
panel1.Controls.Add(control);
control.Dock = DockStyle.Fill;
}
}
I suggest you try adding a button or something to differentiate the UserControls and play around. Have fun! :)
You should create a new Window and show that as opposed to create a page and navigate to it. Then you would call .show() on the new window for it to show.
Then you would change the look of the new window to however you want, the same as editing pages.
If you build your options into a full object model that matches the structure of the options window, then the best way is to use whatever navigation-aware UI binding that your MVVM toolkit uses. The options window would start off as a new root level window to which you would bind the root of your options data model.
So, in short think of the options dialog as a mini-application that uses the same structure as your main MVVM application, but with a different data model root.
If you plan to allow the user to cancel the changes to the options, then you would want your options data model to be clonable so that you can populate the options window with the clone and then swap out the real options with the new data if the user presses OK on the options window. If they select cancel you can just throw the cloned object away and destroy the window.

Docking an Encapsulated Control

I have an encapsulated control in a derived TabPage, and I am having trouble docking it to the form MainForm that contains the derived TabPage.
I've added the TabPage and the control correctly, and they are showing up on MainForm. However, the control is not correctly docked (style: fill). You can verify this by resizing the form.
I've set the property _control.Dock = System.Windows.Forms.DockStyle.Fill and _control.Anchor = Left | Right | Top | Bottom in the derived TabPage's constructor.
Below is the sample of the code:
public class DerivedTab : TabPage {
public DerivedTab(){
...
_control= new BrightIdeasSoftware.TreeListView();
this.Controls.Add(this._control);
_control.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right | System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom;
_control.Dock = System.Windows.Forms.DockStyle.Fill;
...
}
}
In the MainForm, this is the function that creates the derived tab in run-time:
private DerivedTab CreateTab(string name)
{
DerivedTab tab = new DerivedTab(this, name);
tab.SuspendLayout();
MainTab.Controls.Add(tab);
return tab;
}
Anyways, I generated this code using Visual Studio Designer, and the control docks correctly. I, then, created a class for the tabpage (since I will need many and varying number of these tabs) and copied everything relates to tabpage to the CreateTab function. I moved anything relates to the the property of the tabpage into its constructor. I encapsulated the control in the derived TabPage and moved everything related to the control in the derived tabpage.
So, what I am missing? Is it possible to dock the encapsulated control without implementing an eventhandler function?
I found the solution to my own problem. ResumeLayout has to be called after the TabControl adds the TabPage for the TabPage to dock properly.
private DerivedTab CreateTab(string name)
{
DerivedTab tab = new DerivedTab(this, name);
tab.SuspendLayout();
MainTab.Controls.Add(tab);
tab.ResumeLayout();
return tab;
}

add a Tab to Tab control with its content

I am working on an ERP project. it is a button on treeView box and when it is clicking on a button in treeView it must create a Tab with its content (content which is defined-designed before).
I can add a tab programically but how can I design its content?
Adding this to your click event of your treeview should do what you are after:
var contentControl = new ContentControl (); //This is what we will put all your content in
contentControl.Dock = DockStyle.Fill;
var page = new TabPage("Tab Text"); //the title of your new tab
page.Controls.Add(contentControl); //add the content to the tab
TabControl1.TabPages.Add(page); //add the tab to the tabControl
To your project, add a new UserControl called ContentControl (or whatever you need, just using this in my example), and fill it with all the contents you want to appear in your tab.
You have few solutions, the simplest one is to create TabPage, create desired Controls, set up their properties (i.e. Size, Location, Text etc.), add them to the TabPage and then add TabPage to the TabControl.
TabPage tp = new TabPage();
//create controls and set their properties
Button btn1 = new Button();
btn1.Location = new Point(10,10);
btn1.Size = new System.Drawing.Size(30,15);
//add control to the TabPage
tp.Controls.Add(btn1);
//add TabPage to the TabControl
tabControl1.TabPages.Add(tp);
the second solution is to override TabPage in your class, for instance CustomTabPage where you will set up controls in the constructor of the class. Then, when you want to add new TabPage, create your CustomTabPage instance and add it to the TabControl.
public class CustomTabPage : TabPage
{
public CustomTabPage()
{
//create your Controls and setup their properties
Button btn1 = new Button();
btn1.Location = new Point(20, 20);
btn1.Size = new System.Drawing.Size(40, 20);
//add controls to the CustomTabPage
this.Controls.Add(btn1);
}
}
//Create CustomTabPage
CustomTabPage ctp = new CustomTabPage();
tabControl1.TabPages.Add(ctp);
the third solution (the best but the most complicated) is to create your desired UserControl with everything you want on it (you can use Designer help), then create an instance of your UserControl, Create a TabPage and add UserControl on the TabPage. Then add TabPage to the TabControl.
public partial class CustomControlForTabPage : UserControl
{
public CustomControlForTabPage()
{
InitializeComponent();
}
}
//Create CustomControl
TabPage tp = new TabPage();
CustomControlForTabPage ccftp = new CustomControlForTabPage();
//set properties you like for your custom control
tp.Controls.Add(ccftp);
tabControl1.TabPages.Add(ctp);
Add a new user control to the project then use the designer to do controls/layout, then when you click all you do is add a new instance of the user control to the tab - probably docked to fill the tab unless your form's size is fixed.

How do I put a panel of buttons into flow layout panel?

I have a panel of labels, buttons and image that I wish to put into a flow layout panel.
As seen in some tutorial, I understand that it is possible to auto align new and additional buttons into a flow layout panel.
what I would like to ask is that is it possible to put a panel WITHIN a flow layout panel and call multiple instances of the same panel to appear within the flow layout panel.
My panel code would be
this.panelNotification.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panelNotification.Controls.Add(this.button1);
this.panelNotification.Controls.Add(this.lblImage);
this.panelNotification.Controls.Add(this.lblName);
this.panelNotification.Controls.Add(this.lblLinkName);
this.panelNotification.Controls.Add(this.lblLinkLocation);
this.panelNotification.Controls.Add(this.lblLocation);
this.panelNotification.Location = new System.Drawing.Point(3, 3);
this.panelNotification.Name = "panelNotification";
this.panelNotification.Size = new System.Drawing.Size(506, 100);
this.panelNotification.TabIndex = 17;
So is it possible to include the whole panel into a flow layout panel? if yes, how do i do it. thank you.
Yes, you can put a Panel into a FlowLayoutoutPanel.
No, you can't put a control several times into a FlowLayoutoutPanel (in fact you can, but it is only displayed once).
But what you could do is writing some kind of Factory-Method that creates a new Panel with new Buttons/Labels/other Controls etc. every time you call it, and add these new instances to your FlowLayoutpanel. Something like this:
public class Form1
{
private Panel CreateNotificationPanel()
{
var p = new Panel { BackColor = Color.Red };
p.Controls.Add(new Button { Text = "Test" });
return p;
}
private void Form1_Load(System.Object sender, System.EventArgs e)
{
var flp = new FlowLayoutPanel { Dock = DockStyle.Fill };
flp.Controls.Add(CreateNotificationPanel());
flp.Controls.Add(CreateNotificationPanel());
flp.Controls.Add(CreateNotificationPanel());
this.Controls.Add(flp);
}
public Form1() { Load += Form1_Load; }
}
Another (and problably better) approach would be to create a UserControl that contains your Buttons/Labels/etc. instead of using a panel and adding all controls manually. Just create with the Designer and add new instances of the UserControl to the FlowLayoutPanel.

Categories