Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

C# Windows Form Navigation - Total Beginner

Posted on 2017-04-14
9
Medium Priority
?
202 Views
Last Modified: 2017-04-17
I have some programming experience with VB and lots of T-SQL - but this is my first venture into a C# Windows Forms project.

I need a main form and 4 forms that open and close from the main form. The method I want to use is to hold a reference to a form, as per the code below. The problem is that I have tried to add this code to my project and it won't even compile, so I'm obviously doing something very wrong.

I would like a step-by-step guide of hos to get this mechanism, i.e. where do I put this code. I am a little familiar with creating classes and forms etc, just some help in getting this to work may turn on the light for me.

http://stackoverflow.com/questions/3005732/showing-a-hidden-form

The first person who can give me specifics as to how I can implement the above mechanism in a C# Windows Form app gets the points.
0
Comment
Question by:IT Guy
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 3
9 Comments
 
LVL 70

Expert Comment

by:Éric Moreau
ID: 42093096
have you considered using a MDI form with a menu?
0
 

Author Comment

by:IT Guy
ID: 42093098
I have, but I'd like only one form to be displayed at one time - this is proof of principle for me, perhaps when I get more into the app I'm writing I'll implement MDI - but not today.
0
 
LVL 34

Expert Comment

by:it_saige
ID: 42093268
You can hold a reference and call Show()/Hide() on the reference of the form easily enough; e.g. -

Form1.cs -
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;

namespace EE_Q29016206
{
    public partial class Form1 : Form
    {
        readonly List<Form> ChildForms = new List<Form>();
        public Form1()
        {
            InitializeComponent();
        }

        private void OnClick(object sender, EventArgs e)
        {
            if (sender is Button)
            {
                var btn = sender as Button;
                var action = btn.Text.Split(' ');
                if (action.Length == 2)
                {
                    var form = ChildForms.Where(x => x.Name.Equals(action[1])).FirstOrDefault();
                    if (form == null)
                    {
                        switch (action[1])
                        {
                            case "Form2":
                                form = new Form2();
                                break;
                            case "Form3":
                                form = new Form3();
                                break;
                            case "Form4":
                                form = new Form4();
                                break;
                            case "Form5":
                                form = new Form5();
                                break;
                        }
                        ChildForms.Add(form);
                    }

                    switch (action[0])
                    {
                        case "Show":
                            form.Show();
                            btn.Text = string.Format("Hide {0}", form.Name);
                            break;
                        case "Hide":
                            form.Hide();
                            btn.Text = string.Format("Show {0}", form.Name);
                            break;
                    }
                }
            }
        }
    }
}

Open in new window

Form1.Designer.cs -
namespace EE_Q29016206
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.button2 = new System.Windows.Forms.Button();
            this.button3 = new System.Windows.Forms.Button();
            this.button4 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(13, 13);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(259, 23);
            this.button1.TabIndex = 0;
            this.button1.Text = "Show Form2";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.OnClick);
            // 
            // button2
            // 
            this.button2.Location = new System.Drawing.Point(13, 42);
            this.button2.Name = "button2";
            this.button2.Size = new System.Drawing.Size(259, 23);
            this.button2.TabIndex = 1;
            this.button2.Text = "Show Form3";
            this.button2.UseVisualStyleBackColor = true;
            this.button2.Click += new System.EventHandler(this.OnClick);
            // 
            // button3
            // 
            this.button3.Location = new System.Drawing.Point(13, 71);
            this.button3.Name = "button3";
            this.button3.Size = new System.Drawing.Size(259, 23);
            this.button3.TabIndex = 2;
            this.button3.Text = "Show Form4";
            this.button3.UseVisualStyleBackColor = true;
            this.button3.Click += new System.EventHandler(this.OnClick);
            // 
            // button4
            // 
            this.button4.Location = new System.Drawing.Point(13, 100);
            this.button4.Name = "button4";
            this.button4.Size = new System.Drawing.Size(259, 23);
            this.button4.TabIndex = 3;
            this.button4.Text = "Show Form5";
            this.button4.UseVisualStyleBackColor = true;
            this.button4.Click += new System.EventHandler(this.OnClick);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 129);
            this.Controls.Add(this.button4);
            this.Controls.Add(this.button3);
            this.Controls.Add(this.button2);
            this.Controls.Add(this.button1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.Button button2;
        private System.Windows.Forms.Button button3;
        private System.Windows.Forms.Button button4;
    }
}

Open in new window

Form2.cs -
using System;
using System.Windows.Forms;

namespace EE_Q29016206
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        private void OnLoad(object sender, EventArgs e)
        {
            label1.Text = string.Format(label1.Text, Name);
        }
    }
}

Open in new window

Form2.Designer.cs -
namespace EE_Q29016206
{
    partial class Form2
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.label1 = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.label1.Location = new System.Drawing.Point(0, 0);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(133, 20);
            this.label1.TabIndex = 1;
            this.label1.Text = "This is form {0}.";
            // 
            // Form2
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 106);
            this.Controls.Add(this.label1);
            this.Name = "Form2";
            this.Text = "Form2";
            this.Load += new System.EventHandler(this.OnLoad);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Label label1;
    }
}

Open in new window

(rinse and repeat Fomr2 for Form3, Form4 and Form5)...

Produces the following output -
Initial load -Capture.PNGPressing on the button shows the related form -Capture.PNGPressing on the hide button hides the related form.

Caveats -
Becomes harder to manage as you add more controls/forms.  At that point probably makes more sense to either rethink your design or use attribute/helper class driven logic.
Not dialoged, so parent can be accessed at any time.
If a child is closed it is not removed from the collection and the parent form does not visually indicate that the child has closed.

-saige-
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 

Author Comment

by:IT Guy
ID: 42093353
Saige.

That is awesome, obviously you get the points.

....but how would I put a button on form 2 to close form 2? I may need to reopen and close each form more than once.
0
 
LVL 34

Expert Comment

by:it_saige
ID: 42093373
That all depends on what you want the state of Form2 to be when it is closed.

- Do you want Form2 to be disposed or just hidden?
- If you want it to be closed then why hold a reference of it at all.
- If you want it to be hidden then you have to change the functionality of the form from it's closing event (to prevent closing and disposing of the form) as well has trigger an event so that Form1 will update accordingly.

-saige-
0
 

Author Comment

by:IT Guy
ID: 42093376
I want Form2 (or Form3 or Form4) to only be hidden - I understand that C# doesn't like reopening a form it has already disposed of, so we'll hide it.

And then when we close the app we'll check for the state of all forms and close them before closing the main form. Also, from what I understand, we don't need to worry about threading when dealing with forms.
0
 

Author Comment

by:IT Guy
ID: 42093379
And, you're an expert. The following words sound easy, but without an example they're not easy for me at the moment:

- If you want it to be hidden then you have to change the functionality of the form from it's closing event (to prevent closing and disposing of the form) as well has trigger an event so that Form1 will update accordingly.

I would love to see this incorporated in your code.
0
 
LVL 34

Accepted Solution

by:
it_saige earned 2000 total points
ID: 42095367
I understand that C# doesn't like reopening a form it has already disposed of...
One correction, it is not that C# (.NET in general) doesn't like to reopen a form that has been disposed of, it is that a disposed form has been de-referenced; or is in the process of being de-referenced.  You could always create a new form and then open the new form.
Also, from what I understand, we don't need to worry about threading when dealing with forms...
Not entirely true...  Depending upon the user experience you want to provide and the task(s) you are trying to accomplish, multiple forms can (and often do) require multiple threads.

As for the incorporation of an event to handle updating form1 when a child closes/hides; here is one way that this could be accomplished:

Form1.cs -
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;

namespace EE_Q29016206
{
    public partial class Form1 : Form
    {
        readonly Dictionary<Control, BaseForm> ChildForms = new Dictionary<Control, BaseForm>();
        public Form1()
        {
            InitializeComponent();
        }

        private void OnClick(object sender, EventArgs e)
        {
            if (sender is Button)
            {
                var btn = sender as Button;
                var action = btn.Text.Split(' ');
                if (action.Length == 2)
                {
                    BaseForm form;
                    if (!ChildForms.TryGetValue(btn, out form))
                    {
                        switch (action[1])
                        {
                            case "Form2":
                                form = new Form2() { CanClose = false };
                                break;
                            case "Form3":
                                form = new Form3() { CanClose = false };
                                break;
                            case "Form4":
                                form = new Form4() { CanClose = false };
                                break;
                            case "Form5":
                                form = new Form5() { CanClose = true };
                                break;
                        }
                        form.FormStateChanged += OnFormStateChanged;
                        ChildForms.Add(btn, form);
                    }

                    switch (action[0])
                    {
                        case "Show":
                            form.Show();
                            break;
                        case "Hide":
                            form.Hide();
                            break;
                    }
                }
            }
        }

        private void OnClosing(object sender, FormClosingEventArgs e)
        {
            foreach (var frm in ChildForms.Values.Reverse())
            {
                if (!frm.CanClose)
                    frm.CanClose = true;
                // You don't have to unsubscribe from the event here, you could let the event fire once more as it will clean itself up on closing.
                // The benefit to firing the event one more time is in cases where you may have data to save from the closing form and you 
                // want to wait until the event fires to signal that the form has been closed.
                // frm.FormStateChanged -= OnFormStateChanged;
                frm.Close();
            }

            while (ChildForms.Count > 0) ;
        }

        private void OnFormStateChanged(object sender, FormStateChangedEventArgs e)
        {
            if (sender is BaseForm)
            {
                BaseForm frm = sender as BaseForm;
                if (ChildForms.ContainsValue(frm))
                {
                    Button btn = ChildForms.Where(x => x.Value.Equals(frm)).FirstOrDefault().Key as Button;
                    if (btn != null)
                    {
                        switch (e.State)
                        {
                            case FormState.Shown:
                            case FormState.Open:
                                btn.Text = string.Format("Hide {0}", frm.Name);
                                break;
                            case FormState.Hidden:
                            case FormState.Closed:
                                btn.Text = string.Format("Show {0}", frm.Name);
                                if (e.State == FormState.Closed)
                                {
                                    frm.FormStateChanged -= OnFormStateChanged;
                                    ChildForms.Remove(btn);
                                }
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
        }
    }
}

Open in new window

Form1.Designer.cs -
namespace EE_Q29016206
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.button2 = new System.Windows.Forms.Button();
            this.button3 = new System.Windows.Forms.Button();
            this.button4 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(13, 13);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(259, 23);
            this.button1.TabIndex = 0;
            this.button1.Text = "Show Form2";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.OnClick);
            // 
            // button2
            // 
            this.button2.Location = new System.Drawing.Point(13, 42);
            this.button2.Name = "button2";
            this.button2.Size = new System.Drawing.Size(259, 23);
            this.button2.TabIndex = 1;
            this.button2.Text = "Show Form3";
            this.button2.UseVisualStyleBackColor = true;
            this.button2.Click += new System.EventHandler(this.OnClick);
            // 
            // button3
            // 
            this.button3.Location = new System.Drawing.Point(13, 71);
            this.button3.Name = "button3";
            this.button3.Size = new System.Drawing.Size(259, 23);
            this.button3.TabIndex = 2;
            this.button3.Text = "Show Form4";
            this.button3.UseVisualStyleBackColor = true;
            this.button3.Click += new System.EventHandler(this.OnClick);
            // 
            // button4
            // 
            this.button4.Location = new System.Drawing.Point(13, 100);
            this.button4.Name = "button4";
            this.button4.Size = new System.Drawing.Size(259, 23);
            this.button4.TabIndex = 3;
            this.button4.Text = "Show Form5";
            this.button4.UseVisualStyleBackColor = true;
            this.button4.Click += new System.EventHandler(this.OnClick);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 129);
            this.Controls.Add(this.button4);
            this.Controls.Add(this.button3);
            this.Controls.Add(this.button2);
            this.Controls.Add(this.button1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.OnClosing);
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.Button button2;
        private System.Windows.Forms.Button button3;
        private System.Windows.Forms.Button button4;
    }
}

Open in new window

BaseForm.cs -
using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace EE_Q29016206
{
    public partial class BaseForm : Form
    {
        [NonSerialized]
        private FormStateChangedEventHandler _formStateChanged;
        public event FormStateChangedEventHandler FormStateChanged
        {
            add { _formStateChanged += value; }
            remove { _formStateChanged -= value; }
        }

        public bool CanClose { get; set; }

        protected virtual void OnFormStateChanged(object sender, FormStateChangedEventArgs e)
        {
            var handler = _formStateChanged;
            if (handler != null)
                handler(sender, e);
        }

        public BaseForm()
        {
            InitializeComponent();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            if (!CanClose)
            {
                e.Cancel = true;
                Hide();
            }
            base.OnClosing(e);
        }

        protected override void OnClosed(EventArgs e)
        {
            OnFormStateChanged(this, new FormStateChangedEventArgs(FormState.Closed));
            base.OnClosed(e);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            OnFormStateChanged(this, new FormStateChangedEventArgs(FormState.Open));
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            OnFormStateChanged(this, new FormStateChangedEventArgs(Visible ? FormState.Shown : FormState.Hidden));
        }
    }

    public delegate void FormStateChangedEventHandler(object sender, FormStateChangedEventArgs e);
    public class FormStateChangedEventArgs : EventArgs
    {
        public FormState State { get; private set; }

        private FormStateChangedEventArgs() { ;}
        public FormStateChangedEventArgs(FormState State)
        {
            this.State = State;
        }
    }

    public enum FormState : int
    {
        None = 0,
        Shown,
        Hidden,
        Open,
        Closed
    }
}

Open in new window

BaseForm.Designer.cs -
namespace EE_Q29016206
{
    partial class BaseForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.label1 = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.label1.Location = new System.Drawing.Point(0, 0);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(133, 20);
            this.label1.TabIndex = 2;
            this.label1.Text = "This is form {0}.";
            // 
            // BaseForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 106);
            this.Controls.Add(this.label1);
            this.Name = "BaseForm";
            this.Text = "BaseForm";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        protected System.Windows.Forms.Label label1;
    }
}

Open in new window

Form2.cs -
using System;

namespace EE_Q29016206
{
    public partial class Form2 : BaseForm
    {
        public Form2()
        {
            InitializeComponent();
        }

        private void OnLoad(object sender, EventArgs e)
        {
            label1.Text = string.Format(label1.Text, Name);
        }
    }
}

Open in new window

Form2.Designer.cs -
namespace EE_Q29016206
{
    partial class Form2
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // Form2
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 106);
            this.Name = "Form2";
            this.Text = "Form2";
            this.Load += new System.EventHandler(this.OnLoad);
            this.ResumeLayout(false);

        }

        #endregion
    }
}

Open in new window

Rinse and repeat for Form3, Form4 and Form5.
0
 

Author Closing Comment

by:IT Guy
ID: 42095654
Fantastic. This guy knows their stuff and I'm very grateful for his/her assistance.
0

Featured Post

Tech or Treat! - Giveaway

Submit an article about your scariest tech experience—and the solution—and you’ll be automatically entered to win one of 4 fantastic tech gadgets.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Windows 10 Creator Update has just been released and I have it working very well on my laptop. Read below for issues, fixes and ideas.
If you are a mobile app developer and especially develop hybrid mobile apps then these 4 mistakes you must avoid for hybrid app development to be the more genuine app developer.
Windows 8 came with a dramatically different user interface known as Metro. Notably missing from that interface was a Start button and Start Menu. Microsoft responded to negative user feedback of the Metro interface, bringing back the Start button a…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.

650 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question