Multiple .cs files and access to Form - c#

I'm trying to write my first program in C# without the use of a tutorial. To ensure that I adopt from the start good coding practices, I want to create each class in an different .cs file. However, I'm running into some troubles when trying to access the elements of the program in such an .cs file.
For example, I have an Form1.cs with an Label and a Start button. When clicking on the start button, a text should appear in the Label. So:
In Form1.cs I have:
namespace TestProgram
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void startButton_Click(object sender, EventArgs e)
{
WriteToLabel message = new WriteToLabel();
message.WelcomeMessage();
}
}
}
And in my separate WriteToLabel.cs file:
namespace TestProgram
{
public class WriteToLabel
{
public void WelcomeMessage()
{
Form1 myForm = new Form1();
//myForm.. --> myForm doesn't have an 'outputLabel'?
outputLabel.Text = "Welcome!"; // This returns an error: 'The name outputLabel does not exits in the current context'.
}
}
}
'outputLabel' is the (Name) I've given the label, and this is in accordance to the name in Form1.Designer.cs.
Both files are using the same components such as 'using System';.
However, from my WriteToLabel.cs file I can't seem to access the Form which holds my program. I did manage to succeed to create different .cs files in an Console Application, which only added to my confusion. So, I have two questions:
First, how can I access the Form from a separate class (i.e. not an partial class) in a separate file?
Second, is this the good way to do it, or is it inefficient to create multiple instances of different classes?
Any thoughts or ideas are highly welcome,
Regards,

The designer automatically creates controls as private fields, because of that your WriteToLabel class can't access it. You need to change that.
Also a good start would be to change the class to something like that:
namespace TestProgram
{
public class WriteToLabel
{
Form1 form;
public WriteToLabel(Form1 form)
{
this.form = form;
}
public void WelcomeMessage()
{
//Form1 myForm = new Form1();
//myForm.. --> myForm doesn't have an 'outputLabel'?
form.outputLabel.Text = "Welcome!";
}
}
}

You're actually instantiating a new instance of Form1, whereas you need to pass in a reference to your existing instance:
public void WelcomeMessage(Form1 form)
{
form.outputLabel.Text = "Welcome";
}
You also need to ensure that outputLabel is a public (or internal) property/field of Form1 so you can set the value accordingly. Then the calling code is slightly different:
private void startButton_Click(object sender, EventArgs e)
{
WriteToLabel message = new WriteToLabel();
message.WelcomeMessage(this);
}

You need to make sure that Form1.outputLabel has public or internal visibility.
You only need something like a LabelWriter class if the class is going to share a significant amount of state or private methods. If all you have is a bunch of methods that set properties on separate objects, you might as well just keep it as a method on the same object (in this case the Form1 object):
void startButton_Click(object sender, EventArgs e)
{
displayWelcomeMessage();
}
void displayWelcomeMessage()
{
this.outputLabel = "Welcome!";
}

Related

List going back to 0 after new form

I have this class:
public class Observador : iObservador
{
private List<Form> Forms = new List<Form>();
public void DeSubscribirse(Form form)
{
Forms.Remove(form);
}
public void Limpiar()
{
Forms.Clear();
}
public void Subscribirse(Form form)
{
Forms.Add(form);
}
public List<Form> DevolverSubscriptos()
{
return this.Forms;
}
}
Which is used on a base form I have like this:
public partial class FormBase : Form
{
public EE.Observador Watcher = new Observador();
public FormBase()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.Hide();
}
}
Which I use for the rest of my forms to be inherited from.
My idea is to have in all the forms a reference to the object Watcher from every place, with it having a reference for every form which is subscribed to it. So I can do for example, from FormB know that FormA is already subscribed with the method DevolverSubscriptos() (this means return subscribers) and access it to make it visible again after closing FormB.
The problem is that when I start FormB the list of Watcher with the whole forms is set back to 0.
What am I doing wrong? How can I solve it?
public partial class AdminUIGI : FormBase.FormBase
That's how I reference it.
Short answer: you're using an instance field. Each form is a separate instance, hence each has it's own copy of the EE.Observador.
So a quick and dirty fix would be to make this field static, i.e. shared by all instances of the given class. And if you want to improve, you might then consider reading about the Singleton pattern (mainly because you'll see it used a lot - but read on :) ), then read why using Singleton as a global variable is in fact an anti-pattern and move on to reading about dependency injection and IoC - which is how (in vacuum at least) your code should probably end up. (Note: for a quick and dirty solution static field is all you need).
#decPL I made it work with the singleton pattern doing this ` public sealed class Singleton
{
Singleton()
{
}
private static readonly object padlock = new object();
private static Singleton instance = null;
public static EE.Observador watcher = new Observador();
private Usuario userInstance = null;`

Why I can't Invoke from a different class?

My problem is, I can't invoke a message into the TextBox and I can't understand why.
There is a main class and a second class, both with call to the other one.
Where is my error?
using System;
using System.Windows.Forms;
namespace Class_Test___Invoke
{
public partial class MAINFORM : Form
{
public MAINFORM()
{
InitializeComponent();
_INVOKER = this;
}
private MAINFORM _INVOKER;
private static CLASS _CLASS = new CLASS();
private void button1_Click(object sender, EventArgs e)
{
_CLASS._MESSENGER();
}
public void _LOGGING(string _MESSAGE)
{
if (InvokeRequired)
{
_INVOKER.Invoke(new Action<string>(_LOGGING), new object[] { _MESSAGE });
textBox_ausgabe.AppendText(_MESSAGE);
return;
}
else textBox_ausgabe.AppendText(_MESSAGE);
}
}
}
namespace Class_Test___Invoke
{
class CLASS
{
private MAINFORM _MAINFORM = new MAINFORM();
public void _MESSENGER()
{
_MAINFORM._LOGGING("Test");
}
}
}
You are assuming that the _MAINFORM you create in the CLASS constructor is the same instance as the form where the button was clicked, which is not the case. You have a chicken-and-egg problem. Your form creates a CLASS, and the CLASS creates a form. So now you have two different forms. (or two different CLASS instances since you don't show how the first form or CLASS is created)
You need to "connect" the form and the class, either by passing the form to the constructor as a parameter or by some other means.
Finally, I would encourage you to do some research on best practices for class and member names. It's a bit disconcerting for a seasoned C# developer to see names in all caps and prefaced by underscores.

How to move methods to external file in windows form C#

newbie question :(
I'm making a program using windows forms and i have a lot of small methods like this
private void label1_Click(object sender, EventArgs e)
{
textBox1.Select();
}
private void label13_Click(object sender, EventArgs e)
{
textBox13.Select();
}
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
plotGraph(prostokat);
}
in the Form1.cs file and to make the code more transparent, I would like to move these small methods out somewhere to an external file (class?) but I don't really know how to do this. If they were normal methods I would just make a class and create an object of that class and just call the methods using that object but these are functions that "happen" when a user action is performed i.e. a textbox is clicked, so I'm not sure how to make this work.
It is possible to create an extra partial class (separated file) for your Form1 and place your cluttering methods there.
Or you could collapse them with #region
#region UI Handlers
#endregion
The perfect solution would be using some kind of MVVM for WinForms. In that case in your ViewModel you can implement your business logic separately from the code-behind.
Check out this:
https://www.codeproject.com/articles/364485/mvvm-model-view-viewmodel-patte
Hope it helps!
Have a look at your Form class subsection. It most cases it is still a partial class. Create a new .cs file in the same subsection in your project and add another partial form class to it.
You can find additional information here:
Partial Classes and Methods
Sure, you can add a new class to your project (right-click the project in Solution Explorer --> Add Class --> ) and put your methods there. Then you will need to hook the methods up to the controls in code:
I added a static class called "Form Methods" and put a method in there for label1 Click event:
static class FormMethods
{
public static void label1_Click(object sender, EventArgs e)
{
Label label = (Label) sender;
// Try to find the textbox through the label's parent form
TextBox textBox = (TextBox) label.Parent.Controls.Find("textBox1", true).First();
if (textBox != null)
{
textBox.Select();
}
}
}
Then in the Form Designer code, you can hook up the event:
this.label1.Click += new System.EventHandler(FormMethods.label1_Click);
Alternatively, you can make the class part of your original form class, and it will still be a separate file. If you want to do this, you can then make your event a private non-static method, and you would change the class definition to a public partial class:
public partial class Form1 // <-- This used to be: static class FormMethods
{
// This used to be: public static void label1_Click
private void label1_Click(object sender, EventArgs e)
{
. . .
And then hooking up the event looks like:
this.label1.Click += new System.EventHandler(label1_Click);
You can create any number of partial class files mimicking your original and group methods inside as your functionally needs - however, you won't be able to use the designer to directly navigate to your callbacks. That is, if you double click a graphic element or click an event of a graphic element you will have an unexpected behavior: in both cases you will have an event handler generated in your first partial and a hook created to that . . . so you can't directly navigate to those handlers anymore, and you need to go trough your partial files looking for their definitions.
Use partial to split C# code like this.
public partial class Employee
{
public void DoWork()
{
}
}
public partial class Employee
{
public void GoToLunch()
{
}
}

Call method/class from different file

I'm terribly new so I might be completely off track overall with what I'm trying to do.
I don't really know how to ask the question, my english is a bit rocky.
But I have 2 files one containing this:
frmMain.cs
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 WindowsFormsApplication1
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
private void label1_Click(object sender, EventArgs e)
{
Class1 cls = new Class1();
cls.Visibility();
}
}
}
And another file containing this:
Class1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WindowsFormsApplication1
{
public partial class Class1
{
public void Visibility()
{
frmMain c = new frmMain();
c.label1.Visible = false;
}
}
}
What I'm trying to get is that when I'm running the program and clicking label1 I want it to disappear.
But it doesn't. I don't get any errors or anything.
Any help is appreciated :).
Thanks in advance.
First: Why are you trying to let the label on your mainform dissappear by using another class?
I would suggest the following:
private void label1_Click(object sender, EventArgs e)
{
label1.Visible = false;
}
I think the reason why your code isn't working is that inside the function Visibility() of Class1 you are creating a new frmMain and on that frmMain you are setting the visible property of label1 to false. So you are actually working with a different form.
You are instantiating a new, separate form. This means the label is being hidden.. but on a hidden form you have created.
You need to pass the current form instance into your other class:
public void Visibility(frmMain mainForm) {
mainForm.label1.Visible = false;
}
Then call it like this:
new Class1().Visibility(this);
What you're doing is you're creating a second instance of your window (which might not be obvious to you, as you're not displaying it). Then you are hiding the label in your second window. Probably not what you intended in the first place.
What you need to do is to pass a reference to your original form to the method you're calling, or (depending what you want to do) a reference to the control you need to hide:
in Class1:
public void Visibility(Control controlToHide)
{
controlToHide.Visible = false;
}
in frmMain.cs
new Class1.Visibility(this.label1)
few more comments:
Naming: do not use names like Class1, label1; I appreciate this is probably
just 'play around with' kind of code, but such names are completely
unreadable when you try to come back to your code later (or get
someone else to have a look)
Naming 2: try to name your methods to describe what they will do - HideControl, or HideLabel is much better than Visiblity
You may want to read some basic C# tutorials to learn about references, instances, parameters, etc.
Other than that, happy C#-ing :)
You do not want to let Class1 know about frmMain. Change it to something like this:
public class Class1
{
public bool GetVisibility()
{
return false;
}
}
And from your form, call it like this:
private void label1_Click(object sender, EventArgs e)
{
Class1 cls = new Class1();
this.Label1.Visible = cls.GetVisibility();
}
Your current implementation of Class1 initializes a new frmMain, hides that form's Label1, does not do anything with that instance (e.g. it does not Show() it) and then returns, not affecting the already instantiated and shown frmMain instance (the one you instantiate Class1 from).
You can change this by passing the label or even the form into Class1, but that is just bad design.
You may change your code this way:
public partial class FrmMain : Form
{
public frmMain()
{
InitializeComponent();
}
private void label1_Click(object sender, EventArgs e)
{
new Class1().Visibility(this);
}
public void Go()
{
this.label1.Visible = false;
}
}
Then
public partial class Class1
{
public void Visibility(FrmMain form)
{
form.Go();
}
}
You are setting the visibility of the label of another form (one that's not being displayed.
this line of code in the Visibility method creates a new object
frmMain c = new frmMain();
It's of the same type as the form being display, but it's a different object, that's not displayed. If you insert a line after the above
c.Show();
you should see the newly created form and also see that the label disappears
However there's a straight forward fix to your problem. Change the event handler to this
private void label1_Click(object sender, EventArgs e)
{
((Label)sender).Visible = false;
}
The sender object is the control that was clicked, and since the event is attached to the label it self. All you need to do is cast the sender to the type of a Label and then you can access the visible property. Alternatively you could do this:
private void label1_Click(object sender, EventArgs e)
{
this.label1.Visible = false;
}
That uses the current object (aka this) and gets the label from that object.

accessing a function in the Program.cs that initializes my Form1 from my Form1

I've created a server/client application and in my client app i initialized my connection in the Program.cs file in which i also initialize my Form application . How can i, lets say, click on an button on my form and call a function in my Program.cs file ?
Putting stuff in Program.cs is not recommended, you should instead create new files.
If you want to put it in Program.cs you just add a method there, you need to make it static since the Program class is static.
To call it from a button, just double click the button in the designer and an event handler is created.
private void button1_Click(object sender, EventArgs e)
{
Program.YourMethod();
}
The same principle applies if you put the code in another file. Create a namespace and a class in that file.
If you make the class/method non static (that's how you usually do) you need to instantiate your class too.
private void button1_Click(object sender, EventArgs e)
{
var yourObject = new YourClass();
yourObject.YourMethod();
}
Assuming the function is public and static, e.g.
public static void Foo()
{
MessageBox.Show("foo");
}
Simply have such code in the button click event:
Program.Foo();
If you make the method static, you can just call it like this:
class Program
{
// ...
public static void SendMessage(object obj)
{
// Send your message.
}
}
Then call the method:
Program.SendMessage(whatToSend);
to do any inheritance from any class to program.cs, we can not do directly because it will consists only static classes so for that we can get by making access modifier static for example as shown below
private static IinterfaceName xxx;
public program(IinterfaceName xx){
xxx=xx;
}
so using this kind will be helpful

Categories

Resources