My WinForms application has form that contains several tabs. Inside each tab page i want to have another forms. That's how i add form to tab page:
public void InitializeTabs()
{
// Example #1
PlaceForm(FirstTabPage, new OneForm(EntryForm, Settings));
// Example #2
PlaceForm(SecondTabPage, new TwoForm(EntryForm, Settings));
}
Method PlaceForm
public void PlaceForm(TabPage tabPage, Form form)
{
form.TopLevel = false;
form.FormBorderStyle = FormBorderStyle.None;
form.Dock = DockStyle.Fill;
form.AutoScaleMode = AutoScaleMode.Dpi;
if (!tabPage.Controls.Contains(form))
{
tabPage.Controls.Add(form);
tabPage.Dock = DockStyle.Fill;
form.Show();
}
}
Example #1 - works - form added to tab page. But Example #2 - works strangly - if i add existing in project form class to second tab page - form is shown as expected, but when i create new form from wizard
and trying to display it on second tab page - form is not showing.
I finally confused, what i make wrong or where to search solution?
Related
I have a form page with text boxes and data grid view and other forms that contain a tab control. I want to add the first form tab in the second form. I tried to write the code for the form to appear but it is larger than the tab container and doesn't fit. Only half of the form appears.
This is my code:
private void tcMainPage_SelectedIndexChanged(object sender, EventArgs e)
{
if (tcMainPage.SelectedIndex == 0)
{
GTOWN.PrintingPage BookInfo = new PrintingPage();
BookInfo.TopLevel = false;
BookInfo.FormBorderStyle = FormBorderStyle.None;
BookInfo.Dock = DockStyle.Fill;
tpSearch.Controls.Add(BookInfo);
BookInfo.Show();
}
}
this is the form
and that is what appears
Set your main FORM as a Container.
yourForm.IsMdiContainer = true;
Then add the child form to the tabPage:
private void tcMainPage_SelectedIndexChanged(object sender, EventArgs e)
{
if (tcMainPage.SelectedIndex == 0)
{
PrintingPage newFrm = new PrintingPage
{
MdiParent = this,
// This set the form parent as the tabClicked
Parent = tcMainPage.TabPages[0]
};
newFrm.Show();
}
}
my tab form work good in the same code
thank you all my code was correct but the problem was in tab property i deleted the tab and add another one and the code is working now
thank you
I face this issue and I create this if may help
public void addform(TabPage tp, Form f)
{
f.TopLevel = false;
//no border if needed
f.FormBorderStyle = FormBorderStyle.None;
f.AutoScaleMode = AutoScaleMode.Dpi;
if (!tp.Controls.Contains(f))
{
tp.Controls.Add(f);
f.Dock = DockStyle.Fill;
f.Show();
Refresh();
}
Refresh();
}
Forms are top-most objects and cannot be placed inside of other containers.
You may want to refactor your code so that the items on your Form are on a UserControl instead. At that point you can then add that UserControl to both a Form and a TabControl
public UserControl myControl(){ /* copy your current view code here */}
public Form myForm(){
Controls.Add(new myControl());
}
public Form myTabbedForm(){
var tabControl = new TabControl();
var page1 = new TabPage();
page1.Controls.Add(new myControl());
tabControl.TabPages.Add(page1);
this.Controls.Add(tabControl);
}
I have 3 Forms: frmLOGIN, frmREGISTER & frmACCOUNTS
frmLOGIN has two buttons BtnRegister and BtnLogin, when I press BtnRegister it opens up frmREGISTER.
frmREGISTER has 1 button BtnAddAcc, BtnAddAcc is used to add a rows to datagridview(datagridview inside frmACCOUNTS)
frmACCOUNTS has only 1 datagridview inside it, nothing else
BtnRegister code (inside frmLOGIN)
frmREGISTER frm = new frmREGISTER();
frm.Show();
this.Hide();
BtnAddAcc code (inside frmREGISTER)
frmACCOUNTS acc = new frmACCOUNTS
acc.datagridview.Rows.Add(userID,ln,fn,Dateofbirth,address,contactnumber,username,password);
PROBLEM
When I register a user, using the code above, works, when I try to add code like acc.Show(); to open the form and see if it adds the row to the datagridview, and yes it really adds a row. Now when I get back to the login form and press BtnLogin to open up the frmACCOUNTS the datagridview rows are GONE
Reference
I will answer my own question
Answer is that you need to create a CLASS
Class Controller
{
public static frmLOGIN log = new frmLOGIN();
public static frmREGISTER reg = new frmREGISTER();
public static frmACCOUNTS acc = new frmACCOUNTS();
public static void FormOpen(string form_name)
{
if(form_name == "accounts")
{
acc.Show();
}
else if (form_name == "register")
{
reg.Show();
}
else if (form_name == "login")
{
log.Show();
}
}
}
now to use this. you do not need to call the form again inside the other forms you just need to call the class and and the call the form there.
example
let's say, I want to show login form
so I will call
Controller.FormOpen("login");
let's say I want to use the datagridview inside the Accounts form
and put it inside a new variable
Datagridview DGV = Controller.acc.Datagridview1
now you can use the datagridview inside the accounts form as DGV
Conclusion
call the form inside a class so when other forms wants to call/use another form they will be calling the same forms and not making a new one
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
I have a C# Form application that has a TabControl in the main form. This TabControl is used to display multilple TabPages that contain a CustomControl. This CustomControl is just a Panel with a few buttons and a PictureBox.
Here is a picture of my app when it starts up. As you can see the tab control (the white area) is empty:
If the user clicks the "Add Image" button they are presented with an OpenFileDialog to select the image then the addImage method is called with the selected file:
private void doAddImage()
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = Constants.Global.IMAGE_FILE_FILTER();
if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string imageFileName = openFileDialog.FileName;
addImage(imageFileName);
}
}
private void addImage(string imageFileName)
{
// Create a new bitmap and image preview custom control. Then create a new tab
// page and add the custom control to the tab page.
Bitmap bitMap = new Bitmap(imageFileName);
ImagePreviewCustomControl previewControl = new ImagePreviewCustomControl(bitMap);
previewControl.Dock = DockStyle.Fill;
TabPage tabPage = new TabPage(Path.GetFileNameWithoutExtension(imageFileName));
tabPage.Controls.Add(previewControl);
// Insert the new tab page to the right of the currently selected tab page
int selectedTabIndex = imagesTabControl.SelectedIndex;
imagesTabControl.TabPages.Insert(selectedTabIndex + 1, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex + 1;
}
As you can see, in the addImage method I create the Bitmap, CustomControl, and TabPage and then insert it into the TabControl.
I start my application, click the "Add Image" button, everything works just fine.
Here is a picture with a tab page added:
While I am testing my app I don't want to have to add an image manually using the OpenFileDialog every time so in my constructor I just call addImage with some fixed image file name that I want to test with:
public ImageViewerApp()
{
InitializeComponent();
addImage(#"C:\MyImages\Calculator-3-icon.png");
}
The problem I am having is that when I try to add the image in my constructor it doesn't show up in the TabControl. The application starts up blank (like the first picture).
As stated above when the application is already running and I click the "Add Image" button it gets added just fine.
I found a property in the TabControl class called Created which states:
"Gets a value indicating whether the control has been created"
So to try and figure out what's going on I write the value of Created to the console just before I call addImage in the constructor. (I have a custom console for debugging my Form applications.)
public ImageViewerApp()
{
InitializeComponent();
TestConsole.WriteLine(imagesTabControl.Created);
addImage(#"D:\Development\Work\Other\Stardock\Start8\_downloaded\Calculator-3-icon.png");
}
The value of Created just before the call to addImage in the constructor is:
False
I put another console output inside the addImage method:
private void doAddImage()
{
TestConsole.WriteLine(imagesTabControl.Created);
OpenFileDialog openFileDialog = new OpenFileDialog();
...
...
}
The value of Created after the app has started and the user presses the "Add Image" button is:
True
Why is it that the TabControl is not Created inside my constructor (even after the InitializeComponent() call) and the once the application is running it is Created?
=UPDATE========================================================================
Based on the suggestion by Hans Passant I have added the following code to my addImage method:
int selectedTabIndex = -1;
if (imagesTabControl.TabCount > 0)
{
selectedTabIndex = imagesTabControl.SelectedIndex;
}
else
{
selectedTabIndex = imagesTabControl.SelectedIndex + 1;
}
imagesTabControl.TabPages.Insert(selectedTabIndex, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex;
This doesn't work.
===============================================================================
=UPDATE2=======================================================================
int selectedTabIndex = imagesTabControl.SelectedIndex;
if (imagesTabControl.TabCount == 0) selectedTabIndex = -1;
imagesTabControl.TabPages.Insert(selectedTabIndex, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex;
This causes the following Exception:
{"InvalidArgument=Value of '-1' is not valid for 'index'.\r\nParameter name: index"}
===============================================================================
=UPDATE3=======================================================================
I tried the folllowing code:
int selectedTabIndex = imagesTabControl.SelectedIndex;
if (imagesTabControl.TabCount == 0) selectedTabIndex = -1;
imagesTabControl.TabPages.Insert(selectedTabIndex + 1, tabPage);
imagesTabControl.SelectedIndex = selectedTabIndex + 1;
This one doesn't throw an exception but again no tab page added after calling
addImage in the constructor.
===============================================================================
=UPDATE4=======================================================================
I have kindof given up on adding an image in the constructor. So instead I am using an enum RunMode and a variable RUN_MODE of that type. Then, if RUN_MODE == RunMode.TESTI call a method to add a random image when I click the button. (The OpenFileDialog is not used. I just parse through all the image files in the fixed directory IMAGE_DIRECTORY.
enum RunMode { NORMAL, TEST }
private static string IMAGE_DIRECTORY = #"D:\\Work\Images";
...
...
private void doAddImage()
{
if (RUN_MODE == RunMode.TEST)
{
addRandomImage();
return;
}
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = Constants.Global.IMAGE_FILE_FILTER();
if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string imageFileName = openFileDialog.FileName;
addImage(imageFileName);
}
}
private void addRandomImage()
{
string[] allFiles = Directory.GetFiles(IMAGE_DIRECTORY);
List<string> imageFileNames = new List<string>();
foreach (string file in allFiles)
{
bool isImageFile = Constants.Global.IMAGE_EXTENSIONS.Contains(Path.GetExtension(file));
if (isImageFile)
{
imageFileNames.Add(file);
}
}
int randomIndex = new Random().Next(imageFileNames.Count);
addImage(imageFileNames.ElementAt(randomIndex));
}
This works. Now when I click the "Add Image" button during TEST_MODE I skip the
OpenFileDialog and just add a random image.
I would like to understand the issues with TabControl but at this point I just
need to continue development. My current solution works great.
As I person who like to understand everything I would like to use other people's
suggestions so I will keep monitoring this question for a solution.
===============================================================================
JonP's answer gave me the idea to just wait for the window handle to be created before inserting the tab, so I tried some events occuring between Form construction and Tab Control display.
I found it to work with both the Load or Shown events:
Right-click on the Form (the root, not child controls) in the Designer view > Properties > Events (flash icon) > Behavior > enter a method name for the Load or Shown event and confirm. To generate a Load event callback you can also double-click on the Form itself. This should generate something like this:
this.Load += new System.EventHandler(this.Form1_Load);
// or
this.Shown += new System.EventHandler(this.Form1_Shown);
Setup the tabs in the callback:
private void Form1_Load(object sender, EventArgs e)
{
// Add image (this will call imagesTabControl.TabPages.Insert(selectedTabIndex + 1, tabPage))
// This must be done on Load event because Insert requires
// the window handle, which is not ready in the constructor
addImage(#"path_to_image.png");
}
I have had this problem too and have found a workaround; I think it must be a bug with Insert():
Don't use Insert(), it usually does nothing, use Add() instead; this reliably adds a TabPage to the end of the collection.
After adding it swap it with the tab position where you actually want it.
imagesTabControl.TabPages.Add(tabPage);
// Now swap the two tabs:
imagesTabControl.TabPages[imagesTabControl.TabCount - 1] = imagesTabControl.TabPages[selectedTabIndex + 1];
imagesTabControl.TabPage[selectedTabIndex + 1] = tabPage;
Your mileage may vary of course :-)
Stop Press! An even better fix is to read the class's Handle member before calling Insert():
var handle = imagesTabControl.Handle;
Insert() works perfectly after you do that. Obvious isn't it???? The help page for Handle has this possible relevant Remark showing that the object actually does something when you read Handle:
The value of the Handle property is a Windows HWND. If the handle has not yet been created, referencing this property will force the handle to be created.
You could remove the TabControl from the designer and then instead just manually create the TabControl programmatically and add it to the Form immediately after InitializeComponent(). Then after you create the TabControl, call addImage(). Something like:
InitializeComponent();
TabControl tc = new TabControl();
tc.Location = new Point(10, 10);
tc.Size = new Size(100, 100);
tc.Visible = true;
tc.Anchor = (AnchorStyles.Bottom | AnchorStyles.Right | AnchorStyles.Left | AnchorStyles.Top);
this.Controls.Add(tc)
addImage("c:\pathToImage\image.bmp");
I'm new to Visual Studio 2010 and I'm planning to create a Timekeeping system. I'm just want to ask how could I create a form that compose 2 forms in it. For example, if I will click a button it will open a new form inside a form. Please help. Thanks
Form formA = new Form();
formA.IsMdiContainer = true;
Form formB = new Form();
formB.MdiParent = formA;
formB.Show();
You have to work with MDI (Multiple Document Interface), have alook at this article that might help.
You could create custom form, remove all borders, and toolbars to make it look as closely to a panel as possible. Then make that new custom form a MdiContainer / MDI-panel and show forms in that panel, something like the code below will do the job
Mdi-Panel definiton:
public class MdiClientPanel : Panel
{
private Form mdiForm;
private MdiClient ctlClient = new MdiClient();
public MdiClientPanel()
{
base.Controls.Add(this.ctlClient);
}
public Form MdiForm
{
get
{
if (this.mdiForm == null)
{
this.mdiForm = new Form();
/// set the hidden ctlClient field which is used to determine if the form is an MDI form
System.Reflection.FieldInfo field = typeof(Form).GetField("ctlClient", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
field.SetValue(this.mdiForm, this.ctlClient);
}
return this.mdiForm;
}
}
}
Usage:
/// mdiChildForm is the form that should be showed in the panel
/// mdiClientPanel is an instance of the MdiClientPanel
myMdiChildForm.MdiParent = mdiClientPanel1.MdiForm;
I think, this is a very easy way:
Form1 form= new Form1 ();
form.TopLevel = false;
this.Controls.Add(form);
form.Show();
Maybe MDI interface will do what you want..
Here's a tutorial to do that.