Join 118,478 C# Programmers for FREE! Ask your question and get quick answers from experts. There are 961 online right now! We've got more than 500 tutorials and 2,000 snippets. Join and find out why Dream.In.Code is the #1 programming help community on the internet! Registration is fast and FREE... Join Now!
Maybe this is a dumb question... but i actually don't know how to access objects from the GUI i made with visual studio 2008 from another class.
Let's say i have this code:
Form1.cs:
CODE
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms;
namespace ChatzyClient { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } } }
Program.cs:
CODE
using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Windows.Forms;
namespace ChatzyClient { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { ClientEngine myClient = new ClientEngine();
Thread engineThread = new Thread(new ThreadStart(myClient.StartEngine));
// start de engineThread engineThread.Start();
Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); MainForm mainform = new MainForm(); Application.Run(mainform);
} } }
ClientEngine.cs:
CODE
using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace ChatzyClient { class ClientEngine { public void StartEngine() { while (true) { Console.WriteLine("test"); } } } }
So, you don't see it, but i have a few TextBox's like txtMonitor and txtTextInput. In form1.cs i can access the methods of those objects easily of course (like the method txtTextInput.Text) but now my question: how can i access them in the class ClientEngine?
No this isn't a silly question. This is actually a common problem with people fairly new or still learning object oriented principles. Often times people want a class to access the interface elements. This isn't right.
You should never want to tie an object that does something separately to an interface because then it makes the class dependent on that interface. You couldn't then take ClientEngine.cs out of your project and use it in another project without having to create all the controls of your form again in the new project. This binds the class to the interface in a tightly coupled fashion... which is bad for maintainability and reuseability.
What if you later decide to rename your controls or remove the control altogether? You would be forced to go back into the ClientEngine class code and rewrite parts of it. Introducing bugs accidentally along the way.
Instead what you should be thinking is how do I create an instance of my class on the form, use its methods and properties to get information and display that information to the controls on my form? This would be the form USING instances of your object. Your object itself is unaware of the interface or where the data it returns is heading. It is focusing on its job of returning accurate information to a caller.
So for instance... instead of ClientEngine finding the control txtMonitor and sending it the text "test" it should have a public method or property that returns "test" when called. Then in your form, you would...
csharp
ClientEngine ce = new ClientEngine(); txtMonitor.text = ce.getTestText();
Here we are creating an instance of the object and asking it for the "test" text we put in a method called "getTestText". What this does for us is that A.) We could essentially have multiple ClientEngine classes if we wanted B.) Makes ClientEngine loosely coupled to the interface so we could rip out the clientEngine class and use it in other projects "as is" and C.) Allows clientEngine class to focus on not sending info to specific form controls, but instead returning the correct information to a caller it knows nothing about. D.) Since it is loosely coupled, we could create another class (be it a wrapper class or just another class) that could call ClientEngine for info without needing to modify ClientEngine. This other class may not be related to the GUI interface at all, thus writing to controls is invalid.
I hope I am getting the point across. Great question.
As mentioned, tightly coupling objects is often seen as a bad practice. However, loading the rendering layer with a lot of worker code can also be a bad practice. Another approach is to make the elements of the form that need to be updated transparent and then use some kind of controller for the heavy lifting.
Let's assume ChatzyClient contains the object txtTextInput. That object is private, which is good, don't change that. However, we want the value in that box to be externally manipulated. So we "expose" the property out private object with a public property.
csharp
namespace ChatzyClient { public partial class MainForm : Form { // ... public string TextInput { get { return this.txtTextInput.Text; } set { this.txtTextInput.Text = value; } } // ... } }
Now external code can mess with that value. However, in order to mess with it, they need to have it.
csharp
namespace ChatzyClient { class ClientEngine { // form reference holder private MainForm mainForm;
// public ClientEngine(MainForm mainForm) { this.mainForm = mainForm; }
// expose the reference we were constructed with public ChatzyClient.MainForm MainForm { get { return this.mainForm; } }
// methods we wrote to play with the form public void DoSomething() { this.mainForm.TextInput = "Hi Mom"; } } }
A word of warning. There are some issues with Forms and cross threading. Seriously look into the System.Windows.Forms.Timer class if you want to do threading on forms.
And yes, it often confuses me if i code in C# with an already made GUI in Visual Studio 2008. It creates automatically already a program.cs, which has the Main method, and the main method creates a new instance of a mainform which runs as the main thread...
I used to program in Java first, and then it was basically like this: create the first class with the method main in it, and create from there other objects of classes to use the functions/methods it have...
So now with the automatically events made in C# (like click on a button, etc) should i work from the mainform class?
Hope you understand me, my english isn't very good.
You can always change the generated code! You can even write and compile code from text files, if you like. Think of the generated code as a guide, not the law. I often write event listeners by hand; the Timer is a good example. Sometimes I let the GUI make the structure for me.
You would normally handle a button click or similar event in the form that contains the button. However, it's not required. If an external object needs to know about the click, you can expose it with custom public code, or make the button public.
Having the Program.cs launch your main form is a best practice and an improvement over prior versions of Visual Studio. You can certainly manipulate what's there, if you like. Here's an example of exposing a button click.
csharp
public partial class MainForm : Form { public event System.EventHandler SomethingHappend;
private void button1_Click(object sender, EventArgs e) { if (SomethingHappend != null) { SomethingHappend(this, new EventArgs()); } } }
static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false);
MainForm mainform = new MainForm(); mainform.SomethingHappend += new EventHandler(mainform_SomethingHappend); Application.Run(mainform); }
Those are fantastic responses, baavgai and Martyr2. I am going to Feature this topic on the front page. I am sure there are a lot more new programmers that are wondering the very same thing.
Good job!
I am also editing the title to make it more descriptive to the subject matter.
**edit: I see Martyr2 already has already blogged on this very subject. No doubt prompted by the question.
I appreciate the link to the blog jayman. Yeah I was looking for an entry topic and this has been like the 4th or 5th time in the last couple months I have seen such a question. So I figured I would try give more details.