Why I can't Invoke from a different class? - c#

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.

Related

Object reference not set to an instance of an object? But it is? C# [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 6 years ago.
Newbie coder here. Working on a game of Yahtzee but can't figure out why I'm getting this error (object reference not set to instance of object) when I have corrected it already. My 'form' object is null even though I've declared an instance of it in the class constructor and a green line saying it is not being used appears.
public partial class Form1: Form {
public Form1() {
InitializeComponent();
}
private Game game;
public void ShowMessage(string message) {
lblMessage.Text = message;
}
public void StartNewGame() {
game = new Game(this);
}
private void btnRoll_Click(object sender, EventArgs e) {
game.RollDice();
}
class Game {
private Form1 form;
public Game(Form1 form) {
form = new Form1();
}
public void RollDice() {
form.ShowMessage("blahblah");
}
The "NullReferenceException" error appears over form.ShowMessage and I don't know why. I have declared a new instance of the form class in the game constructor which is run when the player selects StartNewGame which runs the StartNewGame method. The easiest way to get it working is to simply add "Form1 form" to the parameter of the RollDice() method in the Game class, and then game.RollDice(this) in the Form1 event handler. But the instruction guide for the assignment states that we shouldn't do that and we are to initialize the Form1 object in the constructor of Game. Please help I'm new and cant understand why this is happening.
Your problem is a naming conflict in your constructor:
public Game(Form1 form)
{
form = new Form1();
}
The parameter has the same name as the form level variable. This means the constructor code is newing up the variable you pass in and not the one at class level. You should either refer to the form variable with this qualifier, or preferably rename it.
A common practice is to use underscore prefix for class level variables:
class Game
{
private Form1 _form;
public Game(Form1 form) {
_form = new Form1();
}
}
Use this in constructor Game Class :
public Game(Form1 form)
{
this.form = form;
}
You are creating a new form instead of assigning the passed in form to its local variable.
class Game {
private Form1 form;
public Game(Form1 form) {
*form = new Form1();*
}
public void RollDice() {
form.ShowMessage("blahblah");
}
You should change the code so the passed in form will be assigned to its local variable like this:
public Game(Form1 form) {
this.form = form;
}
Then it should work.
Don't let your Game class know about the Form that's calling it. That really limits the reusability of your code in the future, since now any Form that tries to use the Game class has to have a ShowMessage method to call.
Instead, just have your RollDice method return a string...
class Game
{
public void RollDice()
{
// do important 'roll dice' stuff...
return "blahblah";
}
}
And then have your Form handle the return value appropriately.
private void btnRoll_Click(object sender, EventArgs e)
{
string message = game.RollDice();
lblMessage.Text = message;
}
That completely gets around the need to pass the Form into your Game class, and avoids a lot of opportunities for getting a NullReferenceException.

C# Correct way to access parent method

I am new to C# and OOP and have researched many of the similar topics but end up more confused than when I started. I need to be able to call a method in a parent class from a child in another namespace.
Below is a (over) simplified example of what I have now and seems to work, but is this the right/best way?
File Form1.cs:
namespace Test1
{
public partial class Form1 : Form
{
NotTest1.Class1 myClass1 = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Start the child class and pass this parent
myClass1 = new NotTest1.Class1(this);
}
public void Form1Function(String text)
{
textBox1.AppendText(text + Environment.NewLine);
}
private void button1_Click(object sender, EventArgs e)
{
// Do some stuff then call Function1 in myClass1
myClass1.Function1();
}
}
}
File Class1.cs:
namespace NotTest1
{
class Class1 {
Test1.Form1 _parent;
public Class1(Test1.Form1 parent) {
_parent = parent;
}
public void Function1()
{
// Do lots of "stuff"
_parent.Form1Function("Got Here");
}
}
}
Examples appreciated, as I am still trying to learn all of the correct terminology.
Thanks
The best way in Class1.cs use using.
using Test1;
namespace NotTest1
{
class Class1 {
Form1 _parent;
public Class1(Form1 parent) {
_parent = parent;
}
public void Function1()
{
// Do lots of "stuff"
_parent.Form1Function("Got Here");
}
}
}
If Class1 needs to call methods on a Form1 instance, then what you have done is perfectly fine, though I don't see how you have parent and child classes here. What you really a Class1 class that happens to accept a Form1 instance in order to call methods on it.
What you did works fine.
Nonetheless, you may want to explore a bit on Events - this way your Parent class may instantiate a child class and subscribe to its events, and your child class may be completely decoupled from your Parent class.
A very nice, clear example is shown on this thread:
Super-simple example of C# observer/observable with delegates

StackOverFlow exception, need a way around infinite loop

I am making an app for a friend, and need the user to "input" a value, and return it to the MySQL code I have. this way, what displays will change.
My problem is this: When I do "Form1 newForm = new Form1();" (this is called in DB_Application)
I get a stackoverflow error.
public partial class Form1
{
private DBApplication DB_App = new DBApplication();
private void InitializeComponent()
{
this.orderID.Text = "";
this.orderID.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.EnterKey);
.....
this.phoneNumber.Text = DB_App.phone_number;
.....
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void EnterKey(object o, KeyPressEventArgs e)
{
if(e.KeyChar == (char)Keys.Enter)
{
//converts the "orderID.Text" to an integer value.
if (!int.TryParse(orderID.Text, out newCurrentID))
MessageBox.Show("not a number");
e.Handled = true;
}
}
}
public class DBApplication : DBInfo
{
Form1 newForm = new Form1(); // infinite loop
public DBApplication()
{
OrderID();
}
private string OrderID ()
{
.... //reads the MySQL info, and outputs the value from the database.
}
}
After the User presses "enter" I need the value to go back into "DB_Application" so the MySQL command may receive it, and output a new value.
As mentioned in your comments and by others, the stack overflow is coming from your DBApplication instantiating a Form1, which in turn instantiates a DBApplication, which in turn instantiates a Form1 and so on.
Rewrite your DBApplication to take a Form1 as part of its constructor rather than instantiating its own, this will avoid the infinite recursion and likely this is want you want since the DBApplication will properly reference the open form:
public class DBApplication
{
private Form1 Form;
public DBApplication(Form1 form)
{
this.Form = form;
}
...
}
public partial class Form1 : Form
{
private DBApplication DB_App;
public Form1()
{
DB_App = new DBApplication(this);
InitializeComponent();
}
...
}
Depending on the rest of your application, you may want to instantiate DB_App after the call to InitializeComponent(). (On second look at your code, it's pretty obvious that the DB_App needs to be assigned before calling InitializeComponent().)
Also, since we don't know the full design/usage of DBApplication, perhaps you need to flip it around where the DBApplication instantiates a Form1, and the Form1 has the existing DBApplication passed in instead.
There are generally better ways of doing this (say via dependency injection), but this should be a simple way without completely breaking the architecture you have now.
If you indeed call new Form1() from DBApplication the StackOverflow comes from new DBApplication() in Form1 (it's an instance variable). How to solve the problem depends on your application logic.

Accesing Richtextbox from a class

I'm trying to append text in my richtextbox which is called ConsoleText. It's not working very well. I'm using a property in my form to access the richtextbox in the Class.
It looks like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//Skipped the rest
public string ACText
{
set
{
ConsoleText.AppendText(value);
}
}
Now from my class's constructor.
public McDonalds(string email, string pass)
{
Form1 f = new Form1();
f.ACText = "test";
}
It's not showing any text in my richtextbox sadly. I know it works, because i can in the property use a messageBox and see that the value is passed into it.
Thanks in advance i really need help with this.
Calling Form1 f = new Form1(); does not give you a reference to an existing form, it creates a new one with blank/default values in the form's controls.
HOW to solve this greatly depends on your design. If you want to tie your class to that form implementation, our class needs either a reference to the form, a reference to the control, or the value of the control that you're interested in passed to it.
For example:
public McDonalds(string email, string pass, Form1 form)
{
form.ACText = "test";
}
A cleaner solution would be to RETURN a value from your McDonalds class and let the FORM set the control value appropriately rather than tying your class to that form class.
you can use Singleton:
Singletons make having single instances easy. They allow for single allocations and instances of data. We review the singleton types. We see one of the fastest implementations. And we review other possibilities.
public partial class Form1 : Form
{
public static Form1 instance = null;
public Form1()
{
instance = this; //add this class to singleton
InitializeComponent();
}
public void Show(string Message)
{
MyConsole.Text = Message;
}
another class:
Form1.instance.Show("blah blah");
Create Delegate in Form1 Class binded method ACText (string val), and Pass the Delegate to McDonalds Class. Fire the Delegate
namespace YourNameSpace
{
public delegate void RichTextBoxDelegate(string text);
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void ACText(string s)
{
ConsoleText.AppendText(s);
}
// In Some Method Call MCDonald's form
public void ShowMcDonalds()
{
RichTextBoxDelegate deleg = new RichTextBoxDelegate(ACText);
MCdonalds ob = new McDonalds(deleg);
ob.show();
}
}
}
Pass the deleg to McDonalds form
Just fire the Delagate
public McDonalds(RichTextBoxDelegate sp)
{
Form1 f = new Form1();
sp("This is Test");
}
deleg("Test value"); // form McDonald's Form

Multiple .cs files and access to Form

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!";
}

Categories

Resources