Alternative MDI or SDI Solution for .NET

March 5, 2008 at 8:24 AMAmer Gerzic

Multiple Document Interface (MDI) is a technique to separate data layer from presentation layer, which is primarily utilized in MFC. As an MFC developer looking to develop applications in .NET, I was searching for a similar concept. My interest was mostly in GUI design, rather than complete MDI/SDI solution. At first, I was very happy to learn that Windows Forms provided assistance in MDI development. As always, I fired up VS.NET 2005 and created sample project. Couple of minutes later, I had MDI-like application, where I could add/remove views very quickly. It felt too good to be true, which later proved that it was. At first I wanted all of my child views to be shown maximized. In addition, I wanted all child views without a control bar. Everything went well, except that my forms could not get rid of control bar. In addition, form resizing did not function properly. As always, I searched the web and found numerous attempts to solve these issues. All solutions suggested following steps:

  1. Do all steps as usual to create MDI parent form;
  2. Child forms should set property ControlBox to false and WindowState to Maximized - these need to be set in child view's load event;

Even though these tips resolved my control box issue, I still had problem with resizing. Every time I switched between forms, newly shown form would not fit exactly into parent from. After experimentation, I realized that the problem disappears if child view is created just before it is shown (intuitively destroyed after it is hidden).

At this point, all my issues were resolved, but I was not happy. Somehow, I was not comfortable with the fact that solution is somewhat "dirty". Also, I wanted solution that would not require child views to be constantly recreated. Finally, with all these workarounds, I was not sure if my code will break in the next release of .NET. But the biggest reason to continue the search for an alternative solution is the fact (I read somewhere - I wish I had reference) that all these features can be accomplished with panel controls. As a matter of fact, some claimed that the solution utilizing control panels worked even better. I felt challenged to such find solution!

As it turns out, the solution was quite simple. At first, I created a windows forms application. Without any modifications to the main form, I added menu control and a ToolStripContainer control. Then I added 2 new forms that I intended to be child views. I knew that some child form properties had to be modified to be embedded into panel control. Following code segment shows all properties that I modified:

public class ChildForm : Form
{
    public ChildForm()
    {
        FormBorderStyle = FormBorderStyle.None;
        TopLevel = false;
        Dock = DockStyle.Fill;
        ShowInTaskbar = false;
        ControlBox = false;
    }
}

As a matter of convenience, I created a base class (shown in code segment above) for my child views that would modify all necessary properties automatically. In this way, I could simply derive all of my child views from the base class and the view would be ready to be used as child window. As I mentioned, child views should be shown in ToolStripContainer's content panel. Content panel is simply a panel, so that adding forms to it is as simple as adding any other control. Following code is executed in Form_Load event of the main form:

private void MainForm_Load(object sender, EventArgs e)
{
    m_ChildView1 = new ChildView1();
    m_ChildView2 = new ChildView2(); 

    toolStripContainer1.ContentPanel.Controls.Add(m_ChildView1);
    toolStripContainer1.ContentPanel.Controls.Add(m_ChildView2);
}

Finally, the code that is responsible for view switching:

protected void SwitchView(ChildForm View)
{
    /* Is the form already activated */
    if ((View == m_ActiveView) || (View == null))
        return; 

    /* Un-merge menu */
    if (m_ActiveView != null)
        ToolStripManager.RevertMerge(MainMenuStrip); 

    /* Show new view */
    View.Show(); 

    /* Merge menu only if the form has a menu */
    if (View.MainMenuStrip != null)
        ToolStripManager.Merge(View.MainMenuStrip, MainMenuStrip); 

    /* Hide active view only after we showed the other one - maybe less flickering */
    if (m_ActiveView != null)
        m_ActiveView.Hide(); 

    /* Set it as active */
    m_ActiveView = View;
}

The code above hardly needs any explanation. At first, we do some sanity checks. Then we un-merge menu from the previous view, we show newly activated view, merge the menu with newly activated view, hide the old view, and finally mark newly activated view as active. Fascinating how new technologies make the life easier!

The sample code included implements all features presented in this post. It is worth mentioning that the solution presented in this article focuses on MDI features and concepts as presented by the .NET technology. It is not full implementation of MDI as presented by MFC library. 

Download

Download Sample Application (20.69 kb)

Posted in: .NET | C#

Tags: , ,

Add comment

biuquote
Loading