locked
how to access main Form component from another class.

    Question

  • hello,

    how are you dudes :)

    I have a problem that has been annoying me for quit some time now, and I was hoping that any one can help me with it.

    it is as follows:

        Let say we have a main form in windows application form and I have on it some text boxes and buttons and so on, and also I have other classes so each class is specialized in doing something.
    so I want on of the text boxes to accessible by all of the other class so they can write to it every thing that happen (status, error.. etc).

    any ideas ?

    if you can provide an example it would be great.

    Thank you,
    Mohammed
    Wednesday, December 31, 2008 7:11 AM

Answers

  • One way to find your form is via Application.OpenForms:
    Form1 GetMainForm()  
    {  
      foreach (Form form in Application.OpenForms)  
        if (form is Form1)  
          return (Form1)form;  
      return null;  

    The other way would be setting a public static variable of Form1 (when you are sure that you will only have one instance of Form1):

    public partial class Form1 : Form  
    {  
      public static Form1 Self;  
     
      public Form1()  
      {  
        Self = this;  
      }  
    }  
     
     
    then you can access your Form1 instance from anywhere by using Form1.Self.
    Wednesday, December 31, 2008 7:53 AM
  • Mohammed AlGomaiz said:

    hello,

    how are you dudes :)

    I have a problem that has been annoying me for quit some time now, and I was hoping that any one can help me with it.

    it is as follows:

        Let say we have a main form in windows application form and I have on it some text boxes and buttons and so on, and also I have other classes so each class is specialized in doing something.
    so I want on of the text boxes to accessible by all of the other class so they can write to it every thing that happen (status, error.. etc).

    any ideas ?

    if you can provide an example it would be great.

    Thank you,
    Mohammed

    Follow Tan's suggestion regarding the static variable.  As long as your code or application become too large, there is no harm in doing that.  The downside is that concept or use of global variables contradicts good OOP practices.

    I would think that one way to do this would be for your form to subsribe to events from the other classes. which in this case are other forms.  The best way would be for the other classes to modify the same instance of a class, or data model.  Pass the model instance into their constructors.  Your main form would need a reference to the same instance of the model.

    As each class modifes the model, the model fires events when properties or state data within the model changes.  Your main form subscribes to these events.  The events carry event args that tell the form how to update itself.  Define as many events as you need.  One for every control that needs updating if you need to.

    Rudedog   =8^D
    Mark the best replies as answers. "Fooling computers since 1971."
    Wednesday, December 31, 2008 2:23 PM
    Moderator
  • I found a simple answer for this it was provided by Mika Wendelius from codeproject.com

    it was as follows :
     
    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    It's not necessarily a good idea to directly update form's controls from several places. However, there are several approaches to this. Since this is your main form, I take it there can be only 1 instance at all time.

    One possibility is to make it a singleton. In that case you would always have access to the form itself. The form would look like:
    public partial class MainForm : Form {
    private static MainForm _theForm;

    private MainForm() {
    InitializeComponent();
    _theForm = this;
    }
    public static MainForm Instance {
    get {
    if (_theForm == null) {
    _theForm = new MainForm();
    }
    return _theForm;
    }
    }
    ...


    Now when you start the application instead of creating the form you refer to it's Instance:
    Application.Run(MainForm.Instance);


    When you want to access it's properties or methods you always use Instance. For example if you want to get Height, you would have:
    System.Windows.Forms.MessageBox.Show(MainForm.Instance.Height.TowString());


    So now you can write your own properties on the main form and access them via Instance.

    Hope this helps

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Thank you all :)
    Sunday, January 11, 2009 7:12 PM

All replies

  • One way to find your form is via Application.OpenForms:
    Form1 GetMainForm()  
    {  
      foreach (Form form in Application.OpenForms)  
        if (form is Form1)  
          return (Form1)form;  
      return null;  

    The other way would be setting a public static variable of Form1 (when you are sure that you will only have one instance of Form1):

    public partial class Form1 : Form  
    {  
      public static Form1 Self;  
     
      public Form1()  
      {  
        Self = this;  
      }  
    }  
     
     
    then you can access your Form1 instance from anywhere by using Form1.Self.
    Wednesday, December 31, 2008 7:53 AM
  • Mohammed AlGomaiz said:

    hello,

    how are you dudes :)

    I have a problem that has been annoying me for quit some time now, and I was hoping that any one can help me with it.

    it is as follows:

        Let say we have a main form in windows application form and I have on it some text boxes and buttons and so on, and also I have other classes so each class is specialized in doing something.
    so I want on of the text boxes to accessible by all of the other class so they can write to it every thing that happen (status, error.. etc).

    any ideas ?

    if you can provide an example it would be great.

    Thank you,
    Mohammed

    Follow Tan's suggestion regarding the static variable.  As long as your code or application become too large, there is no harm in doing that.  The downside is that concept or use of global variables contradicts good OOP practices.

    I would think that one way to do this would be for your form to subsribe to events from the other classes. which in this case are other forms.  The best way would be for the other classes to modify the same instance of a class, or data model.  Pass the model instance into their constructors.  Your main form would need a reference to the same instance of the model.

    As each class modifes the model, the model fires events when properties or state data within the model changes.  Your main form subscribes to these events.  The events carry event args that tell the form how to update itself.  Define as many events as you need.  One for every control that needs updating if you need to.

    Rudedog   =8^D
    Mark the best replies as answers. "Fooling computers since 1971."
    Wednesday, December 31, 2008 2:23 PM
    Moderator
  • Tan Silliksaar said:

    One way to find your form is via Application.OpenForms:

    Form1 GetMainForm()  
    {  
      foreach (Form form in Application.OpenForms)  
        if (form is Form1)  
          return (Form1)form;  
      return null;  

    The other way would be setting a public static variable of Form1 (when you are sure that you will only have one instance of Form1):

    public partial class Form1 : Form  
    {  
      public static Form1 Self;  
     
      public Form1()  
      {  
        Self = this;  
      }  
    }  
     
     
    then you can access your Form1 instance from anywhere by using Form1.Self.


    so far every thing is clear, but can anyone give me an example of how to implement this ?   for the first part, because I can't use static variables or set static variables since the program would be adding an removing most of time.

    Thank you in advance

    and thank you Rudedog2 for your effort. :)

    Wednesday, January 07, 2009 11:13 AM
  • To contribute to the subscribing and publishing events option, you can also use the observer, observable pattern it complements the subscribing to event solution above. But if you love patterns, you can dig into the observer observable.


    Your Form becomes an observable
    The other classes becomes observers

    Once there is a state changed event in your textboxes you will have to notify all register observers of the chnages.

    Here is a simple work through :

    1 
    2    public interface IObserver 
    3    { 
    4        void Update(TextBox textBox); 
    5    } 
    6 
    7    //The form is an observable 
    8    public class MyForm : Form 
    9    { 
    10        TextBox textBox = new TextBox(); 
    11        IList<IObserver> observers = new List<IObserver>(); 
    12 
    13        public void AddObserver(IObserver observer) 
    14        { 
    15            observers.Add(observer); 
    16        } 
    17 
    18        public void NotifyTextChanged() 
    19        { 
    20            foreach (IObserver observer in observers) 
    21                observer.Update(textBox); 
    22        } 
    23    } 
    24 
    25    public class TextLengthObserver : IObserver 
    26    { 
    27        public void Update(TextBox textBox) 
    28        { 
    29            if (string.IsNullOrEmpty(textBox.Text)) 
    30                MessageBox.Show("The Textbox is empty"); 
    31        } 
    32    } 
    33 
    34    public class TextTrimObserver : IObserver 
    35    { 
    36        public void Update(TextBox textBox) 
    37        { 
    38            textBox.Text.Trim(); 
    39        } 
    40    } 


    You can then add your observers anytime during runtime of your form. All you need to do is the following :

    1            MyForm myForm = new MyForm(); 
    2            myForm.AddObserver(new TextLengthObserver()); 
    3            myForm.AddObserver(new TextTrimObserver()); 


    Agility. http://salakoahmed.blogspot.com
    Wednesday, January 07, 2009 12:08 PM
  • Ahmed,
    I like that simple implementaton.  It doesn't actually use events, which is a good thing.  Events would complicate it for absolute beginners.  Here's a more complex sample that uses events I just whipped up.

    using System;  
    using System.Collections.Generic;  
    using System.ComponentModel;  
    using System.Data;  
    using System.Drawing;  
    using System.Text;  
    using System.Windows.Forms;  
     
    namespace SampleMVC  
    {  
        public partial class Form1 : Form, IModelObserver, IModelView  
        {
            #region Add these controls with Form Designer  
            //  
            //private System.Windows.Forms.ProgressBar progressBar1;  
            //private System.Windows.Forms.NumericUpDown numericUpDown1;  
            //private System.Windows.Forms.Label label1;  
            //private System.Windows.Forms.Label label2;  
            //private System.Windows.Forms.NumericUpDown numericUpDown2;  
            //private System.Windows.Forms.Label label3;  
            //private System.Windows.Forms.NumericUpDown numericUpDown3;  
            //  
            #endregion  
     
            DataController controller;  
            private ViewEventArgs vea;  
            internal event ViewHandler<IModelView> Changed;  
            private Timer timer;  
            private bool timerTick;  
     
            public Form1()  
            {  
                InitializeComponent();  
            }
            #region Event Handlers  
            private void Form1_Load(object sender, EventArgs e)  
            {  
                this.vea = new ViewEventArgs(75, 0, 50);  
                this.timerTick = false;  
                this.timer = new Timer();  
                this.timer.Tick += new EventHandler(timer_Tick);  
                this.SetTimerInterval(vea.Rate);  
                controller = new DataController(this);  
                controller.Start();  
            }  
     
            private void SetTimerInterval(decimal rate)  
            {  
                this.timer.Enabled = false;  
                this.timer.Interval = (int)(rate * 5);  
                this.timer.Enabled = true;  
                this.timer.Start();  
            }  
     
            private void timer_Tick(object sender, EventArgs e)  
            {  
                this.timer.Enabled = false;  
                switch (timerTick)  
                {  
                    case false:  
                        this.progressBar1.Value = (int)this.vea.MinValue;  
                        this.timerTick = true;  
                        break;  
                    case true:  
                        this.progressBar1.Value = (int)this.vea.MaxValue;  
                        this.timerTick = false;  
                        break;  
                }  
                this.SetTimerInterval(vea.Rate);  
            } 
            #endregion  
     
     
            #region IModelObserver Members  
     
            void IModelObserver.DataModel_Changed(DataModel sender, ModelEventArgs e)  
            {  
                this.numericUpDown2.Value = e.MaxValue;  
                this.numericUpDown3.Value = e.MinValue;  
                this.numericUpDown1.Value = e.Rate;  
                this.SetTimerInterval(e.Rate);  
                return;  
            }
            #endregion  
     
     
            #region IModelView Members  
     
            event ViewHandler<IModelView> IModelView.Changed  
            {  
                add  
                {  
                    this.Changed += value;  
                }  
                remove  
                {  
                    this.Changed -= value;  
                }  
            }
            #endregion  
     
     
            #region Private Methods  
            private void OnChanged(ViewEventArgs mea)  
            {  
                if (this.Changed != null)  
                {  
                    this.Changed.Invoke(this, mea);  
                }  
            }  
     
            private void numericUpDown3_ValueChanged(object sender, EventArgs e)  
            {  
                this.vea.MinValue = this.numericUpDown3.Value;  
                this.OnChanged(this.vea);  
            }  
     
            private void numericUpDown2_ValueChanged(object sender, EventArgs e)  
            {  
                this.vea.MaxValue = this.numericUpDown2.Value;  
                this.OnChanged(this.vea);  
            }  
     
            private void numericUpDown1_ValueChanged(object sender, EventArgs e)  
            {  
                this.vea.Rate = this.numericUpDown1.Value;  
                this.OnChanged(this.vea);  
            }
            #endregion  
     
        }  

    using System;  
    using System.Collections.Generic;  
    using System.Text;  
     
    namespace SampleMVC  
    {  
        class DataController  
        {  
            DataModel model;  
            IModelView view;  
     
            public DataController(IModelView form)  
            {  
                // without data control  
                //this.model = new DataModel(75, 25, 50);  
                ;  
                // with data control  
                this.model = new DataAccessLayer(75, 25, 50);  
                this.view = form;  
                this.model.Attach((IModelObserver)form);  
                this.view.Changed += new ViewHandler<IModelView>(view_Changed);  
            }  
            public void Start()  
            {  
                ViewEventArgs vea = new ViewEventArgs(model.MaxValue, model.MinValue, model.Rate);  
                this.view_Changed(view, vea);  
            }  
     
            void view_Changed(IModelView sender, ViewEventArgs e)  
            {  
                model.MaxValue = e.MaxValue;  
                model.MinValue = e.MinValue;  
                model.Rate = e.Rate;  
            }  
        }  
    }  
     

    One more post.
    Mark the best replies as answers. "Fooling computers since 1971."
    Wednesday, January 07, 2009 2:52 PM
    Moderator
  •  
    using System;  
    using System.Collections.Generic;  
    using System.Text;  
     
    namespace SampleMVC  
    {  
        public delegate void ModelHandler<T>(T sender, ModelEventArgs e);  
        public delegate void ViewHandler<T>(T sender, ViewEventArgs e);  
     
        interface IModelObserver  
        {  
            void DataModel_Changed(DataModel sender, ModelEventArgs e);  
        }  
        interface IModelView  
        {  
            event ViewHandler<IModelView> Changed;  
        }  
     
        class ModelEventArgs : EventArgs  
        {  
            public decimal MaxValue;  
            public decimal MinValue;  
            public decimal Rate;  
     
            public ModelEventArgs(  
                decimal MaxValue,   
                decimal MinValue,  
                decimal Rate)  
            {  
                this.MaxValue = MaxValue;  
                this.MinValue = MinValue;  
                this.Rate = Rate;  
            }  
        }  
        class ViewEventArgs : EventArgs  
        {  
            public decimal MaxValue;  
            public decimal MinValue;  
            public decimal Rate;  
     
            public ViewEventArgs(  
                decimal MaxValue,  
                decimal MinValue,  
                decimal Rate)  
            {  
                this.MaxValue = MaxValue;  
                this.MinValue = MinValue;  
                this.Rate = Rate;  
            }  
        }  
    }  
     

    using System;  
    using System.Collections.Generic;  
    using System.Text;  
     
    namespace SampleMVC  
    {  
        class DataModel  
        {
            #region Fields and Properties  
            protected decimal maxValue;  
            public virtual decimal MaxValue  
            {  
                get 
                {  
                    return maxValue;  
                }  
                set 
                {  
                    this.maxValue = value;  
                    this.e.MaxValue = value;  
                    //this.OnChanged(e);  
                }  
            }  
            protected decimal minValue;  
            public virtual decimal MinValue  
            {  
                get 
                {  
                    return minValue;  
                }  
                set 
                {  
                    this.minValue = value;  
                    this.e.MinValue = value;  
                    //this.OnChanged(e);  
                }  
            }  
            protected decimal rate;  
            public virtual decimal Rate  
            {  
                get 
                {  
                    return rate;  
                }  
                set 
                {  
                    this.rate = value;  
                    this.e.Rate = value;  
                    this.OnChanged(e);  
                }  
            }  
            protected ModelEventArgs e = new ModelEventArgs(100, 0, 50);
            #endregion  
     
     
            public event ModelHandler<DataModel> Changed;  
     
            public DataModel(  
                decimal MaxValue,  
                decimal MinValue,  
                decimal Rate)  
            {  
                this.MaxValue = MaxValue;  
                this.MinValue = MinValue;  
                this.Rate = Rate;  
                this.e = new ModelEventArgs(MaxValue, MinValue, Rate);  
            }  
     
            public virtual void Attach(IModelObserver view)  
            {  
                this.Changed += new ModelHandler<DataModel>(view.DataModel_Changed);  
            }  
              
            public virtual void Detach(IModelObserver view)  
            {  
                this.Changed -= new ModelHandler<DataModel>(view.DataModel_Changed);  
            }  
              
            public virtual void OnChanged(ModelEventArgs mea)  
            {  
                if (this.Changed != null)  
                {  
                    this.Changed.Invoke(this, mea);  
                }  
            }  
              
        }  
     
        class DataAccessLayer : DataModel  
        {  
            public DataAccessLayer(  
                decimal MaxValue,  
                decimal MinValue,  
                decimal Rate)  
                : base(MaxValue, MinValue, Rate)  
            {  
                return;  
            }  
            public override decimal MaxValue  
            {  
                get 
                {  
                    return base.MaxValue;  
                }  
                set 
                {  
                    CheckMaxValue(value);  
                }  
            }  
     
              
            public override decimal MinValue  
            {  
                get 
                {  
                    return base.MinValue;  
                }  
                set 
                {  
                    CheckMinValue(value);  
                }  
            }  
     
              
            public override decimal Rate  
            {  
                get 
                {  
                    return base.Rate;  
                }  
                set 
                {  
                    CheckRate(value);  
                }  
            }  
     
            private void CheckRate(decimal value)  
            {  
                if ((value >= 25) && (value <= 75))  
                {  
                    base.Rate = value;  
                }  
                if ((value < 25) && (value > 75))  
                {  
                    base.Rate = 50;  
                }  
            }  
            private void CheckMaxValue(decimal value)  
            {  
                if ((value >= this.minValue +10) && (value <= 100))  
                {  
                    base.MaxValue = value;  
                }  
            }  
            private void CheckMinValue(decimal value)  
            {  
                if ((value >= 1) && (value <= this.maxValue -10))  
                {  
                    base.MinValue = value;  
                }  
            }  
        }  
     
    }  
     

    =9^D
    Mark the best replies as answers. "Fooling computers since 1971."
    Wednesday, January 07, 2009 2:54 PM
    Moderator
  •  I suggest that you make the progressbar style to be "continuous".
    Mark the best replies as answers. "Fooling computers since 1971."
    Wednesday, January 07, 2009 2:57 PM
    Moderator
  • Rudedog2 said:

     I suggest that you make the progressbar style to be "continuous".


    Mark the best replies as answers. "Fooling computers since 1971."



    My form looks like this.

    Label3  NumericUpDown3
    Label2  NumeridUpDown2
    -----------------------------------
    |  ProgressBar                     |
    -----------------------------------
    Label1  NumeridUpDown1
    Mark the best replies as answers. "Fooling computers since 1971."
    Wednesday, January 07, 2009 6:54 PM
    Moderator
  • Ahmed Salako said:

    To contribute to the subscribing and publishing events option, you can also use the observer, observable pattern it complements the subscribing to event solution above. But if you love patterns, you can dig into the observer observable.


    Your Form becomes an observable
    The other classes becomes observers

    Once there is a state changed event in your textboxes you will have to notify all register observers of the chnages.

    Here is a simple work through :

    1 
    2    public interface IObserver 
    3    { 
    4        void Update(TextBox textBox); 
    5    } 
    6 
    7    //The form is an observable 
    8    public class MyForm : Form 
    9    { 
    10        TextBox textBox = new TextBox(); 
    11        IList<IObserver> observers = new List<IObserver>(); 
    12 
    13        public void AddObserver(IObserver observer) 
    14        { 
    15            observers.Add(observer); 
    16        } 
    17 
    18        public void NotifyTextChanged() 
    19        { 
    20            foreach (IObserver observer in observers) 
    21                observer.Update(textBox); 
    22        } 
    23    } 
    24 
    25    public class TextLengthObserver : IObserver 
    26    { 
    27        public void Update(TextBox textBox) 
    28        { 
    29            if (string.IsNullOrEmpty(textBox.Text)) 
    30                MessageBox.Show("The Textbox is empty"); 
    31        } 
    32    } 
    33 
    34    public class TextTrimObserver : IObserver 
    35    { 
    36        public void Update(TextBox textBox) 
    37        { 
    38            textBox.Text.Trim(); 
    39        } 
    40    } 


    You can then add your observers anytime during runtime of your form. All you need to do is the following :

    1            MyForm myForm = new MyForm(); 
    2            myForm.AddObserver(new TextLengthObserver()); 
    3            myForm.AddObserver(new TextTrimObserver()); 


    Agility. http://salakoahmed.blogspot.com


    you can't just create a new instance of the main form, the debugger won't allow it, I tried that.

    even if this working fine, I don't want it to update or access that new instance of MyForm I need to access the defult instance that visual studio create for you.

    thanks any way, it is always good to know something new.

    Sunday, January 11, 2009 5:53 AM
  • Rudedog2 said:

    Rudedog2 said:

     I suggest that you make the progressbar style to be "continuous".


    Mark the best replies as answers. "Fooling computers since 1971."



    My form looks like this.

    Label3  NumericUpDown3
    Label2  NumeridUpDown2
    -----------------------------------
    |  ProgressBar                     |
    -----------------------------------
    Label1  NumeridUpDown1
    Mark the best replies as answers. "Fooling computers since 1971."


    Thank you man, but I need time to understand what you posted.

    for a start can you in brief explain what are these lines of code for :

        public delegate void ModelHandler<T>(T sender, ModelEventArgs e);
        public delegate void ViewHandler<T>(T sender, ViewEventArgs e);


    Sunday, January 11, 2009 6:03 AM
  • I found a simple answer for this it was provided by Mika Wendelius from codeproject.com

    it was as follows :
     
    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    It's not necessarily a good idea to directly update form's controls from several places. However, there are several approaches to this. Since this is your main form, I take it there can be only 1 instance at all time.

    One possibility is to make it a singleton. In that case you would always have access to the form itself. The form would look like:
    public partial class MainForm : Form {
    private static MainForm _theForm;

    private MainForm() {
    InitializeComponent();
    _theForm = this;
    }
    public static MainForm Instance {
    get {
    if (_theForm == null) {
    _theForm = new MainForm();
    }
    return _theForm;
    }
    }
    ...


    Now when you start the application instead of creating the form you refer to it's Instance:
    Application.Run(MainForm.Instance);


    When you want to access it's properties or methods you always use Instance. For example if you want to get Height, you would have:
    System.Windows.Forms.MessageBox.Show(MainForm.Instance.Height.TowString());


    So now you can write your own properties on the main form and access them via Instance.

    Hope this helps

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Thank you all :)
    Sunday, January 11, 2009 7:12 PM
  • Mohammed AlGomaiz said:

    I found a simple answer for this it was provided by Mika Wendelius from codeproject.com

    it was as follows :
     
    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    It's not necessarily a good idea to directly update form's controls from several places. However, there are several approaches to this. Since this is your main form, I take it there can be only 1 instance at all time.

    One possibility is to make it a singleton. In that case you would always have access to the form itself. The form would look like:

    public partial class MainForm : Form {
    private static MainForm _theForm;

    private MainForm() {
    InitializeComponent();
    _theForm = this;
    }
    public static MainForm Instance {
    get {
    if (_theForm == null) {
    _theForm = new MainForm();
    }
    return _theForm;
    }
    }
    ...


    Now when you start the application instead of creating the form you refer to it's Instance:
    Application.Run(MainForm.Instance);


    When you want to access it's properties or methods you always use Instance. For example if you want to get Height, you would have:
    System.Windows.Forms.MessageBox.Show(MainForm.Instance.Height.TowString());


    So now you can write your own properties on the main form and access them via Instance.

    Hope this helps

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Thank you all :)



    Take another look.  Take the time that you say you need.  There's only one instance of the form.  I do not know where you got that impression.  That is an Aggregate Pattern known as MVC, Model View Controller.  My data class could be a database or anything else you might need. and the data is abstracted form the form's "view".  Abstraction!

    Your link is not a thread, nor a solution to anything that I can see.  It's the info page for someone.  Psst, your sample resembles the Singleton Pattern.

    The MVC pattern abstracts the data from the view by using a third class, the controller.  Take another look.  Events provide the "connections", not concrete methods.

    Hope this helps.

    Rudedog  =8^D
    Mark the best replies as answers. "Fooling computers since 1971."
    Sunday, January 11, 2009 9:07 PM
    Moderator
  • ...and if you are looking for how I reference the form from other classes, give it up. 

    My sample works the other way around.  The form subscribes to events that fire.  The events provide that tell the form how to update its' display.  Now the same data and controller classes can be made to work with various types of view classes with very little or even no modification.
    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, January 12, 2009 2:42 PM
    Moderator