Sunday, July 18, 2010

Avoid Duplicate Detail Forms in MDI programs

In a MDI Windows Forms/CRUD application, I don't want to display the same Detail form more than once at the same time. What if the user saves the address on one form and the email on another? Even if you can trust the user to do the right thing, it just feels icky to have more than 1 form for "John Smith" up at the same time.

It is less dangerous to have duplicate list forms, but I still don't like to gunk up the application with extra forms hanging around.

This code is a modernization of some code I used a couple of years ago. I am using Generics and Extension methods to reduce the amount of code I used in the old .NET 2.0 code!

using System.Windows.Forms;
namespace AvoidDupeForms
{
    /// <summary>
    /// A Detail Form is a form that can display a single record.
    /// In this example, there can me more than 1 of these loaded
    /// at once, as long as a record is only loaded once.
    /// </summary>
    public interface IDetailForm
    {
        /// <summary>
        /// Get the Id loaded in this form
        /// </summary>
        int Id { get; }
        /// <summary>
        /// Set the id for the form to load
        /// </summary>
        /// <param name="id">Id # to be loaded</param>
        void SetId(int id);
    }
    public static class FormsUtil
    {
        /// <summary>
        /// Reveal a form, load a new one if one doesn't yet exist 
        /// in the context of this MDI 
        /// </summary>
        /// <typeparam name="T">The type of the form to be revealed</typeparam>
        /// <param name="thisForm">
        /// The calling form (used to get MdiParent to be searched)
        /// </param>
        /// <example>
        /// <![CDATA[
        /// // As an extention method
        /// this.RevealForm<ListForm>();
        /// // The oldfashioned way
        /// FormsUtil.RevealForm<ListForm>(this);
        /// ]]>
        /// </example>
        public static void RevealForm<T>(this Form thisForm) 
            where T : Form, new()
        {
            Form MdiParent = thisForm.GetMdiParent();
            if (MdiParent != null)
            {
                foreach (Form frm in MdiParent.MdiChildren)
                {
                    if (frm.GetType() == typeof(T))
                    {
                        frm.BringToFront();
                        return;
                    }
                }
                T flf = new T();
                flf.MdiParent = MdiParent;
                flf.Show();
            }
        }
        /// <summary>
        /// Reveal a form with a given detailId, load a new one if 
        /// one doesn't yet exist in the context of this MDI 
        /// NOTE: > 1 instance of T can exist, but only
        /// 1 fore each IDetailForm.Id
        /// </summary>
        /// <typeparam name="T">The type of the form to be revealed</typeparam>
        /// <param name="thisForm">
        /// The calling form (used to get MdiParent to be searched)
        /// </param>
        /// <param name="detailId">The ID of the Detail record to be displayed</param>
        /// <example>
        /// <![CDATA[
        /// // As an extention method
        /// this.RevealDetailForm<DetailForm>(42);
        /// // The oldfashioned way
        /// FormsUtil.RevealDetailForm<DetailForm>(this, 42);
        /// ]]>
        /// </example>
        public static void RevealDetailForm<T>(this Form thisForm, int detailId) 
            where T : Form, IDetailForm, new()
        {
            Form MdiParent = thisForm.GetMdiParent();
            if (MdiParent != null)
            {
                foreach (Form frm in MdiParent.MdiChildren)
                {
                    if (frm.GetType() == typeof(T))
                    {
                        T saFrm = (T)frm;
                        if (saFrm.Id == detailId)
                        {
                            saFrm.BringToFront();
                            return;
                        }
                    }
                }
                T modify = new T();
                modify.MdiParent = MdiParent;
                modify.SetId(detailId);
                modify.Show();
            }
        }
        /// <summary>
        /// Gets the MdiParent for a given form
        /// (it could be self)
        /// </summary>
        /// <param name="thisForm">
        /// The calling form (used to get MdiParent to be searched)
        /// </param>
        /// <returns>
        /// The MdiParent of thisForm, or null if thisForm has no parent
        /// </returns>
        /// <example>
        /// <![CDATA[
        /// // As an extention method
        /// Form MdiParent = thisForm.getMdiContainer();
        /// // The oldfashioned way
        /// Form MdiParent = FormsUtil.getMdiContainer(thisForm);
        /// ]]>
        /// </example>
        public static Form GetMdiParent(this Form thisForm)
        {
            if (thisForm.IsMdiContainer)
                return thisForm;
            if (thisForm.IsMdiChild)
                return thisForm.MdiParent;
            return null;
        }
    }
}