I want to make a panel contain a MDI form. I want to put MainWin into a Panel (progPanel) that is in another form of DesktopApp. I have used this C# Panel As MDI Container
I cannot recode the MainWin without MDI because that would take forever and I would lose some functionality.
Canvas.MainWin canvasForm = new Canvas.MainWin();
MdiClientPanel mdiClientPan = new MdiClientPanel();
canvasForm.MdiParent = mdiClientPan.MdiForm;
progPanel.Controls.Add(mdiClientPan);
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;
}
}
}
I get the error Form cannot be both an MDI child and MDI parent on line canvasForm.MdiParent = mdiClientPan.MdiForm;. I have tried using DesktopApp.ActiveForm.MdiParent and changing Form in MdiClientPanel to Canvas.MainWin, but nothing is working. Any suggestions?
You cannot do this.
The error message should have been clear enough. So should have been the answer to the other question that you linked.
MDI has been considered obsolete for many years now. Users find it excessively confusing, and there are much better paradigms for unifying multiple windows within a single container. Consider, for example, a tab control. Users are already familiar with this, since every browser in existence uses tabs to display multiple web pages.
Yes, rewriting the application to avoid MDI will take time. But it is your only option, because your idea won't work. And there's an additional benefit to the user.
To be honest, I'm not really sure why you would want an MDI form inside of a panel in the first place. Consider a floating toolbox window as an alternative.
Related
I am making a game using Windows Forms, and I feel that the easiest way to make different screens (Main Menu, Settings, Etc...) is using a separate form for each screen. I have looked up up many different ways to do this. Many people talk of using form2.Show(); this.Hide();, however, this creates a new popup window.
People have also suggested using this.IsMdiContainer = true; to create a new window inside of the current window, but this is also not the functionality I want.
EDIT: Another question, multiple-guis-one-window, explains slightly that this can be achieved using UserControls, but does not elaborate with any examples, or what I should do.
I want to completely replace the current form's functionality with that of a new form.
Is there a way to achieve this? If not, is there a good alternative?
As I understood, you want to keep the same form and change the data inside that form (to not get the effect that your form was closed and reopened again).
The problem is windows form does not support such thing directly (at least not in an optimal way), I would use another UI frameworks for that. However, if you want to stick though with windows forms, you may use GroupBox or Panel tools (available from windows form design tools in Visual studio). Here you can group your elements as required, and show/hide the group/panel as required.
That is one of the best available solution for windows form AFAIK.
You want to open child forms within main form then you should try this i have create it without any User Control.
I have manage one parent form and two child forms. child forms should be open within parent form.
frmMain(Parent Form)
Set frmMain Property as Following
WindowState = System.Windows.Forms.FormWindowState.Maximized
I have take 3 panel in frmMain window.
pnlMenu (For Display Menu)
Set pnlMenu.Dock = System.Windows.Forms.DockStyle.Top property
Set height of this panel as you require.
pnlMain (For Display Child Forms)
Set pnlMain.Dock = System.Windows.Forms.DockStyle.Fill property
pnlFooter (For Footer Section)
Set pnlFooter.Dock = System.Windows.Forms.DockStyle.Bottom; property
Set height of this panel as you require.
I have set menubar in pnlMenu(Click on that menu for display child form in pnlMain)
frmMain.cs
public void BindFormIntoMainForm(Form Main)
{
Main.TopLevel = false;
Main.WindowState = FormWindowState.Maximized;
Main.AutoScroll = true;
pnlMain.Controls.Clear();
pnlMain.Controls.Add(Main);
pnlMain.Refresh();
Main.Show();
}
private void childToolStripMenuItem_Click(object sender, EventArgs e)
{
frmChildForm1 ChildForm1 = new frmChildForm1();
BindFormIntoMainForm(ChildForm1);
}
private void childForm2ToolStripMenuItem1_Click(object sender, EventArgs e)
{
frmChildForm2 ChildForm2 = new frmChildForm2();
BindFormIntoMainForm(ChildForm2);
}
BindFormIntoMainForm method responsible for display child form in main window.
frmChildForm1 & frmChildForm2(ChildForm)
Set both form Property as Following
FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
Now when you click on Child Form 1 Menu then display following output:
when you click on Child Form 2 Menu then display following output:
I think it can be helpful for you.
If I were to navigate between 2 forms (or more), it would be like this:
Main Menu to second form:
Form2 form2 = new Form2(this) // Instantiate form and pass form data to next form
Hide();
Second form:
Form1 form;
public Form2(Form1 form1)
{
this.form1 = form1; //Take in previous form's data
}
Navigating forward will Hide() the current form while navigating backwards will Close() the current form.
But what if I am in the 3rd, 4th... nth form and I wish to go back to the main menu? Is there some kind of way to close all of my hidden forms?
Or is there a proper method to navigate between forms?
In my opinion you should use Interfaces to change data between forms. This let's you stay more independent and your Form2 just get the data it needs. For example:
public interface IForm1 //You should find better naming
{
void Edit(); //Method for edit some data
List<T> DataList {get;} //List with some relevant data
}
public Form Form1 : IForm1
{
public void Edit(){ //Your edit logic}
public List<T> DataList {get{return myGrid.DataSource as List<T>;}}
}
public Form Form2
{
private IForm1 formData;
public Form2(IForm1 formData)
{
formData = formData;
}
}
Further i would think about your idea to have so much forms. I think one MainForm with a TabControl as first element is better way to go in many cases. You can create a UserControl for each TabPage and just switch the TabPage instead of poping up Forms all the time.
UPDATE
This Picture maybe clarify what i mean. The TabPageHeader are all invisible (in image i make it visible for clarification). If Login succeed you just switch the TabPage.
TabControl.SelectedTabPage = tabPageMainScreen;
So it feels more fluent to the user and you don't have the problem you describe. But i would recommend to separate the Form by different UserControls to keep it simple.
UPDATE 2
On Winforms you can hide the TabHeader as suggested in this post.
Example:
tabControl.ItemSize = new Size(0, 1);
tabControl.SizeMode = TabSizeMode.Fixed;
It's a bit ugly that the default TabControl don't has regular way but it works fine.
I would create a view model from the data in the first form and then supply it in a method on the second form.
public class Form1ViewModel {
public int Age {get; set;}
public string Name {get; set;}
}
//method on Form1
public void NavigateToForm2()
{
var vm = new Form1ViewModel{ Age = 32, Name = "Test name"};
var form2 = new Form2();
form2.SetViewModel(vm);
form2.Show();
}
Also to close the forms take a look at this link.
I would recommend taking a look into MVVM pattern because that handles the navigation, instantiation of the forms (views). A library to start with is mvvmfx. There are also other libraries for MVVM.
While Sebi and Mihail has given great ways for a proper navigation, I have did some practice on my own and found several solutions.
As what Sebi mentioned, a TabControl with one main form is the better way to go in many cases as it is more fluent, does not have forms popping up all the time.
Another way is to only preserve the instance of your parent(main) form:
Navigating from a child form to another will pass the parent form and values of your data (if required), before closing the form (Once closed, all resources created is disposed).
However in some cases where you need to maintain the values for a previous child form (So that all user input does not need to be re-entered again), You have to also pass the child form and hide it instead of closing it.
One thing that confused me when I opened the question was that I had initially thought that navigating forward in forms should always use Hide();, and not Close();.
To close all forms except the main form (Might be useful for those who have a similar design concept as mine):
List<string> currentform = new List<string>();
foreach (Form form in Application.OpenForms)
{
if (form.Name != "Form1")
{
currentform.Add(form.Name);
}
}
foreach (string formName in currentform)
{
Application.OpenForms[formName].Close();
}
I'm trying to implement some complement views inside my application and I would like to have a better layout control over them. I don't know how to explain in words what my desired functionality is, so I made it through with some photoshop help, hoping you could give me a hand to implement it.
My application now looks like this:
(i need reputation to post images so.. sorry for the links)
http://i59.tinypic.com/2ikv8m1.jpg
When I minimize the modeless form which is focused in the previous image, I would like to be able to see it (and handle it to maximize or close) inside my main form as I show in the image below (made it in photoshop)
http://i58.tinypic.com/1e28go.jpg
Hope someone can lead my into a solution and thanks for the support.
EDIT: I need to be able to move that form outside my main form, even to a different monitor.
If you don't want to use the MDI approach, then set TopLevel of the modeless Form to false and add it to the main Forms Controls collection before showing it:
Form frm = new Form();
frm.TopLevel = false;
this.Controls.Add(frm);
frm.Show();
*Obviously changing Form to the correct type of your modeless form.
If i understand what you are trying to do, you want to minimize a certain form but still see it within your app (im assuming like Excel or Word)
You can do something similar to what Idle_Mind said, but enclose both in a Form instead of the parent.
Form fParent = new Form();
fParent.Dock = DockMode.Fill;//i think this is the syntax. Use this if you want the form to fill to the screen
Form fChild = new Form();
fChild.TopLevel = false;
fParent.Controls.Add(fChild);
fChild.Show();
Here, it should minimize to the lower left part of the parent form. You can then size the parent to whatever you want it to be.
All, I have a WinForms MDI control and in it I dock several child windows. When I first did this I managed (somehow) to get rid of the window list (shown above the tabbed forms below)
I am not talking about the double window menu (on the right) I know that this is due to a bug in the WinForms control and that if you add MdiChild elements in the Load event instead of the Constructor, this behaviour resolves itsef (see this post for details).
Here I am talking about the menu strip itself, I don't want it! How do I get rid of it? Any advice is much appreciated...
Note: I am adding MdiChild forms in the following way:
foreach (Form mdiChild in MdiChildForms)
{
mdiChild.MdiParent = this;
mdiChild.Show();
}
where MdiChildForms is a List<Form>.
Here is the possible solution:
public MainForm() {
IsMdiContainer = true;
InitializeComponent();
this.MainMenuStrip = new MenuStrip(); // create our own menu strip
this.MainMenuStrip.Visible = false;
}
I have a Windows Forms application that opens MDI child forms. When I select those forms, I need to set or render its windowstate to Maximized. The problem is, when I navigate between the open forms, it reverts back to the normal window state, and when I set the window state to maximized again, it shows the transition from normal to maximized state and it doesn't look nice.
How can a Windows application be created that have an MDI parent form that opens many MDI childs in maximized window state?
Here's an answer based on using the MDI "Parent Form and Child Form paradigm," with the following assumptions :
you have a MenuStrip control 'Dock = 'Top on your MDIParentForm, and you've implemented the automatic MDI &Window menu handler as described in : How to: Create an MDI Window List with MenuStrip
you are creating new child forms that :
a. do not have a MaximizeBox, MinimizeBox, etc., but may have ControlBox (for closing them)
b. these child forms may be resizable or not : we won't consider the implications of that here.
You want these MDIChildForms to display maximized in the MDIParent Form, but not to obscure the MDIParentForm's menu.
Okay : assuming you have all your child Forms fully designed, "waiting in the wings" : we might see some code like this in your MDIParentForm code :
// create instances of your child forms
Form2 f2 = new Form2();
Form3 f3 = new Form3();
Form4 f4 = new Form4();
Form5 f5 = new Form5();
private void MDIParentForm1_Load(object sender, EventArgs e)
{
f2.Text = "subForm1";
f3.Text = "subForm2";
f4.Text = "subForm3";
f5.Text = "subForm4";
f2.MdiParent = this;
f3.MdiParent = this;
f4.MdiParent = this;
f5.MdiParent = this;
f2.Dock = DockStyle.Fill;
f3.Dock = DockStyle.Fill;
f4.Dock = DockStyle.Fill;
f5.Dock = DockStyle.Fill;
f2.Show();
f3.Show();
f4.Show();
f5.Show();
}
At this point, the dock style 'Fill applied to the child forms will make them full-screen, and keep them from obscuring the MDIParentForm menu : and the menu will allow you to auto-select which one is frontmost.
Now, if you want to do fancier stuff : like resizing the child Forms, tiling them, cascading them. You are going to have to change the 'Dock property of these child windows : and then you can make use of the built-in MDI paradigm window arranging facilities as described here : How to: Arrange MDI Child Forms
And if you want to create multiple instances of one type of pre-defined child form : How to Create MDI Child Forms ... see the example on how to use a 'New menu entry : may prove useful.
If you want the window state to always be maximized, I'd recommend switching away from an MDI Form. A TabControl may work better, in that case.
MDI forms have quite a few usability issues, which is why they are not commonly used anymore, and tend to be replaced with other controls/options.
After reading Reeds answer and especially your comment:
problem with tabcontrol is, i have a
lot of controls used per child form
Maybe this will help:
Don't put your controls into a Winform. Instead encapsulate them into a UserControl (maybe it already works by changing your inheritance from Form to UserControl).
Now put every UserControl on it's own TabPage and set its Dock property to Fill. Now you are able to change each UserControl on it's own, without any interference to another control on another TabPage (as far as you don't built in any connection).
If you intend to give up on MDI, you could have a look at docking frameworks like WeifenLuo or DigitalRune. These are free, for other options you can have a look here: http://windowsclient.net/downloads/folders/controlgallery/tags/Windows+Forms+Docking+Windows/default.aspx
EDIT:
If I remember well, DigitalRune allows the usage of windows forms as containers for docked content so the migration effort would be smaller.