Pass Values from Form -> Class -> Form C# - c#

I have 2 Forms: V.Batch and V.BatchEdit and a Class: M.Batch
In V.Batch there is a DataGrid. I want to pass the value I get from the DataGrid to V.BatchEdit and the get set method is in M.Batch.
The problem here is that the value isn't passed properly in V.BatchEdit. It returns 0.
Here is the code
V.Batch:
M.Batch bt;
public Batch()
{
bt = new M.Batch();
InitializeComponent();
}
private void metroButton3_Click_1(object sender, EventArgs e)
{
bt.batchNum = Convert.ToInt32((metroGrid2.CurrentCell.Value).ToString());
V.BatchEdit bEdit = new V.BatchEdit();
this.Hide();
bEdit.Show();
}
M.Batch:
public int batchNum;
public int BatchNum
{
set { batchNum = value; }
get { return batchNum; }
}
V.BatchEdit
static M.Batch bt = new M.Batch();
DataSet a = bt.getBatch(bt.batchNum);
public BatchEdit()
{
db = new Database();
InitializeComponent();
System.Windows.Forms.MessageBox.Show(bt.batchNum.ToString() + "Batchedit");
try
{
metroTextBox1.Text = a.Tables[0].Rows[0][2].ToString();
}
catch (Exception exceptionObj)
{
MessageBox.Show(exceptionObj.Message.ToString());
}
}
I'm new to coding and c#. I'm not sure if I placed static even though it should not be static or what.

Yes, you are using static improperly here.
The easiest way to see what's going wrong is to notice that you are calling new M.Batch() twice. That means you have two different instances of M.Batch in your application. And nowhere in your code do you attempt to share those instances.
What you should be doing is passing your instance of M.Batch from one form to another, e.g. in the constructor:
// V.Batch
bt.batchNum = Convert.ToInt32((metroGrid2.CurrentCell.Value).ToString());
V.BatchEdit bEdit = new V.BatchEdit(bt);
this.Hide();
bEdit.Show();
// V.BatchEdit
private M.Batch bt;
private DataSet a;
public BatchEdit(M.Batch batch)
{
this.bt = batch;
this.a = this.bt.getBatch(bt.batchNum)
// Rest of your code here.
}

If You don't need the 'M.Batch' class for something else and you only use it for passing the value to V.BaychEdit, just declare a public property in V.BatchEdit like you did in M.Batch and use it like this:
V.BatchEdit bEdit = new V.BatchEdit();
bEdit.BatchNum = Convert.ToInt32((metroGrid2.CurrentCell.Value).ToString());
Your problem is that although your using statics you're still assigning a new instance to the static field.

Related

Calling a class's method from Windows form application

I am trying to call a method with the same name of its class (AHPModel) but accepts an integer argument, from a Windows form by creating an instance of the class, but it gives me an error of "Object reference not set to an instance of an object", please could you help!
Thank you.
In the Form:
private void button6_Click(object sender, EventArgs e)
{
try
{
AHPModel model = new AHPModel(3, 3);
model.AddCriteria(criteria);
model.AddCriterionRatedChoices(0, night);
model.AddCriterionRatedChoices(1, act);
model.AddCriterionRatedChoices(2, cost);
model.CalculateModel();
GeneralMatrix calcCriteria = model.CalculatedCriteria;
GeneralMatrix results = model.ModelResult;
GeneralMatrix choices = model.CalculatedChoices;
}
catch (System.Exception excep)
{
MessageBox.Show(excep.Message);
}
}
My Class
public class AHPModel
{
public AHPModel(int n)
{
}
public void CalculateModel()
{
CalculatePriorities();
CalculateChoices();
CalculateFinalResult();
}
}
That is happening because you have not created the parmeterized constructor for
AHPModel model = new AHPModel(3, 3);
You can do the AHPModel model = new AHPModel(3, 3); when you have class with constructor like below
public class AHPModel
{
public AHPModel(int n)
{
}
public AHPModel(int n,int n)
{
}
public void CalculateModel()
{
CalculatePriorities();
CalculateChoices();
CalculateFinalResult();
}
}
I just realised that I was passing null values of arrays that are locally declared to the method. But now I am able to access the targeted method from my windows form.

Adding list to listbox one by one

I need to add my list to my listbox. I searched through all the questions on this site but none work I always get things like listbox1.spelers in my listbox.
Here is the code I have now.
private void btnAdd_Click(object sender, EventArgs e)
{
Speler speler1 = new Speler(tbNaam.Text, tbAge.Text);
List<Speler> spelers = new List<Speler>();
spelers.Add(speler1);
listBox1.DataSource = spelers;
}
Also tried with the ToArray but it still didn't work.
SOLVED
You're re-binding the control to a list of exactly one element every time. So the control will only ever have one element.
Keep the list in a higher scope. For example, if this class is persistent in memory (that is, not a web application) then make it a class-level member:
private List<Speler> spelers = new List<Speler>();
private void btnAdd_Click(object sender, EventArgs e)
{
Speler speler1 = new Speler(tbNaam.Text, tbAge.Text);
spelers.Add(speler1);
listBox1.DataSource = spelers;
// maybe call listBox1.DataBind() here? it's been a while since I've had to use forms
}
That way you're always adding another element to the same list, instead of creating a new list every time.
If you are using Windows Forms application, you can use a BindingDource:
Speler speler1 = new Speler(tbNaam.Text, tbAge.Text);
List<Speler> spelers = new List<Speler>();
spelers.Add(speler1);
var bs = new BindingSource();
bs.DataSource = spelers;
listBox1.DataSource = bs;
Good example is here : Console App
using System;
namespace Enumeration
{
using System;
using System.Collections;
// implements IEnumerable
class ListBoxTest : IEnumerable
{
private string[] strings;
private int ctr = 0;
// private nested implementation of ListBoxEnumerator
private class ListBoxEnumerator : IEnumerator
{
// member fields of the nested ListBoxEnumerator class
private ListBoxTest currentListBox;
private int index;
// public within the private implementation
// thus, private within ListBoxTest
public ListBoxEnumerator(ListBoxTest currentListBox)
{
// a particular ListBoxTest instance is
// passed in, hold a reference to it
// in the member variable currentListBox.
this.currentListBox = currentListBox;
index = -1;
}
// Increment the index and make sure the
// value is valid
public bool MoveNext()
{
index++;
if (index >= currentListBox.strings.Length)
return false;
else
return true;
}
public void Reset()
{
index = -1;
}
// Current property defined as the
// last string added to the listbox
public object Current
{
get
{
return(currentListBox[index]);
}
}
} // end nested class
// Enumerable classes can return an enumerator
public IEnumerator GetEnumerator()
{
return (IEnumerator) new ListBoxEnumerator(this);
}
// initialize the listbox with strings
public ListBoxTest(params string[] initialStrings)
{
// allocate space for the strings
strings = new String[8];
// copy the strings passed in to the constructor
foreach (string s in initialStrings)
{
strings[ctr++] = s;
}
}
// add a single string to the end of the listbox
public void Add(string theString)
{
strings[ctr] = theString;
ctr++;
}
// allow array-like access
public string this[int index]
{
get
{
if (index < 0 || index >= strings.Length)
{
// handle bad index
}
return strings[index];
}
set
{
strings[index] = value;
}
}
// publish how many strings you hold
public int GetNumEntries()
{
return ctr;
}
}
public class EnumerationTester
{
public void Run()
{
// create a new listbox and initialize
ListBoxTest currentListBox =
new ListBoxTest("Hello", "World");
// add a few strings
currentListBox.Add("Who");
currentListBox.Add("Is");
currentListBox.Add("John");
currentListBox.Add("Galt");
// test the access
string subst = "Universe";
currentListBox[1] = subst;
// access all the strings
foreach (string s in currentListBox)
{
Console.WriteLine("Value: {0}", s);
}
}
[STAThread]
static void Main()
{
EnumerationTester t = new EnumerationTester();
t.Run();
}
}
}

Manipulate form control properties from other classes?

I'm trying to manipulate the properties of a control in my main form via one of my classes.
Basically I'm trying to update a label, I've set it to public like so:
public Label DicerollLabel;
And I'm refering to my main form from my class like this:
private Form1 _mainForm;
When I try to access the label and set a value to it like this:
_mainForm.DicerollLabel.Text = "Hello World!";
I get the following error:
An unhandled exception of type 'System.NullReferenceException' occurred.
My entire code to the two files involed is below:
Main Form:
namespace BettingGame
{
public partial class Form1 : Form
{
private Player _playerOne;
private Player _playerTwo;
private DiceRoller _diceRoller;
private decimal _prizePool;
private Random _random;
public int ProgressBar
{
get {return progressBar1.Value;}
set { progressBar1.Value = value; }
}
public Label DicerollLabel;
public Form1()
{
InitializeComponent();
_playerOne = new Player() {PlayerName = "x", PlayerFunds = 100};
_playerTwo = new Player() {PlayerName = "x", PlayerFunds = 100};
_diceRoller = new DiceRoller();
_random = new Random();
playerOneFundsLabel.Text = "Funds: " + _playerOne.PlayerFunds.ToString(CultureInfo.CurrentCulture) + "$";
playerTwoFundsLabel.Text = "Funds: " + _playerTwo.PlayerFunds.ToString(CultureInfo.CurrentCulture) + "$";
PrizeAmountLabel.Text = "";
diceRollLabel.Text = "";
}
private void button1_Click(object sender, EventArgs e)
{
_playerOne.PlayerBetAmount = (decimal) playerOneBet.Value;
_playerTwo.PlayerBetAmount = (decimal) playerTwoBet.Value;
if (!(_playerOne.PlayerBetAmount <= 0) || !(_playerTwo.PlayerBetAmount <= 0)
&& (_playerOne.PlayerBetAmount > 0) && (_playerTwo.PlayerBetAmount > 0))
{
_prizePool = _playerOne.PlayerBet() + _playerTwo.PlayerBet();
PrizeAmountLabel.Text = _prizePool.ToString(CultureInfo.CurrentCulture);
FormUpdate();
}
else
{
MessageBox.Show("Invalid bets! Bet amount must be greater than 0!");
}
}
private void FormUpdate()
{
playerOneFundsLabel.Text = "Funds: " + _playerOne.PlayerFunds.ToString(CultureInfo.CurrentCulture) + "$";
playerTwoFundsLabel.Text = "Funds: " + _playerTwo.PlayerFunds.ToString(CultureInfo.CurrentCulture) + "$";
}
private void button2_Click(object sender, EventArgs e)
{
//for (int i = 0; i < 45; i++)
//{
// int value = _random.Next(1, 50);
// diceRollLabel.Text = value.ToString();
// diceRollLabel.Update();
// Thread.Sleep(50);
//}
_diceRoller.RollDice();
}
}
}
And the DiceRoller class:
namespace BettingGame
{
class DiceRoller
{
private Random _random = new Random();
private Form1 _mainForm;
public void RollDice()
{
_mainForm.DicerollLabel.Text = "Hello World!";
}
}
What am I doing wrong? Note that I'm only in my second week of programming so I'm still learning!
change your DiceRoller class to define the following constructor:
public DiceRoller(Form1 host) {
_mainForm = host;
}
Then in your Form1 where you create an instance of DiceRoller:
private DiceRoller _diceRoller = new DiceRoller(this);
This is a really terrible design long term. It's definitely code I would expect from a new programmer - so don't feel bad. You're doing fine.
In the future try to think about reusability. By making your DiceRoller dependent on Form1 (and the specific controls in Form1) you are faced with two challenges later on:
1. You can not use DiceRoller in another project (or possibly even in your same project) without modification.
2. If you change any of the controls that DiceRoller depends upon you must also change DiceRoller.
I'll let you think about how you might avoid these issues. I'm sure if you need help with them you'l post another question. :)
You need to have a reference to the Form1 created. This is not named Form1, but within the Form1 you can refer to it using the keyword "this" and you can pass that into a constructor for your DiceRoller class.
class DiceRoller
{
private Random _random = new Random();
private Form1 _mainForm;
public DiceRoller(Form1 f)
{
_mainForm = f;
}
public void RollDice()
{
_mainForm.DicerollLabel.Text = "Hello World!";
}
}
Then you call this within your constructor for Form1:
public Form1()
{
InitializeComponent();
_playerOne = new Player() {PlayerName = "x", PlayerFunds = 100};
_playerTwo = new Player() {PlayerName = "x", PlayerFunds = 100};
_diceRoller = new DiceRoller(this);
....
These are the minimal changes needed to make your code work. However, you might consider other changes such as passing in the label instead of the form.

Change a form label text value when setting a static int

I'm trying to change a form label's text value (frmWebInput.ConnectedUserCount.Text) when changing a static int value from another static void...
Basically: It's a simple web server, and I'm trying to keep track of the connected users when each page is served. It seems to be working, but the form label is not getting changed though?
/**
* #type int Total connected users.
*/
private static int _connectedUsers = 0;
public static int connectedUsers {
get { return _connectedUsers; }
set
{
_connectedUsers = value;
frmWebInput MyForm = new frmWebInput();
MyForm.ConnectedUserCount.Text = String.Format("Connected Users: {0}", value);
}
}
public static void clientListener()
{
while (true)
{
try
{
HttpListenerContext request = listener.GetContext();
ThreadPool.QueueUserWorkItem(processRequest, request);
}
catch (Exception e) { }
}
}
public static void processRequest(object listenerContext)
{
try
{
connectedUsers = connectedUsers + 1;
}
}
Is this a WinForms application running on the web server? Or is this a WebForm?
In any event, you never show the form:
frmWebInput MyForm = new frmWebInput();
MyForm.ConnectedUserCount.Text = String.Format("Connected Users: {0}", value);
Every time the value is set, you create a new instance of frmWebInput and set the text on that instance. But you never show it. If one is already shown elsewhere in the application, you never set its text.
You need a reference to the instance of the form being shown. Something like:
private static frmWebInput MyForm { get; set; }
private static int _connectedUsers = 0;
public static int connectedUsers {
get { return _connectedUsers; }
set
{
_connectedUsers = value;
MyForm.ConnectedUserCount.Text = String.Format("Connected Users: {0}", value);
}
}
And, of course, that reference would have to be set with the instance of the form. Since it's static it would have to be within the static initializer. Either that or instead of an auto-implemented property it can just be a get which dynamically fetches the instance of the form. It's difficult to advise on the best approach since I don't know how this code interacts with the form instance.

Access TextBox from Static method in C#?

I have 2 classes: MyForm and Database
In MyForm I have a method to change a label text to show error:
public void printError(string text){
label1.Text = text;
}
My Database class needs to access that method too, so I make it static:
public static void printError(MyForm form, string text){
form.label1.Text = text;
}
Now the problem is, how do I call that method from Database class?
This question I found said that I need to pass MyForm into Database's contructor like this:
class MyForm : Form{
Database db;
public Form(){
db = new Database(this);
}
}
class Database{
MyForm form;
public Database(MyForm f){
form = f;
}
...
//then I can access the printError like this
MyForm.printError(form, "You got error");
}
I tried that and it freezes the form. Any other solution?
Thanks
Here is a very simple example of how you can achieve this without your data layer knowing about your UI:
class MyForm : Form
{
Database db;
public Form()
{
db = new Database(this);
}
public void DoSomething()
{
var errors = db.Login("", "");
if (errors.Any())
label1.Text = errors.First(); // Or you can display all all of them
}
}
class Database
{
public List<string> Login(string username, string password)
{
var errors = new List<string>();
if (string.IsNullOrEmpty(username))
errors.Add("Username is required");
if (string.IsNullOrEmpty(password))
errors.Add("Password is required");
[...]
return errors;
}
}
Like #Matthew Ferreira and others have stated the design is not idea, but here's something to get you started.
class MyForm : Form
{
public void SomeMethod()
{
var dataAccess = new Repository();
dataAccess.ExecuteQuery();
if (dataAccess.Exceptions.Any())
{
// display your error messages
form.label1.Text = dataAccess.Exceptions.Select(x => x.ToString());
}
}
}
class Repository
{
private readonly HashSet<Exception> _exceptions = new HashSet<Exception>();
public IEnumerable<Exception> Exceptions
{
get { return _exceptions; }
}
public int ExecuteQuery()
{
var numberOfRecordsAffected = 0;
try
{
// do something
}
catch (Exception ex)
{
// normall catching exceptions is a bad idea
// and you should really catch the exception at the
// layer best equiped to deal with it
_exceptions.Add(ex);
}
// but, for the purpose of this example we might want to add some logic to try the query on another database ????
try
{
// do something
}
catch (Exception ex)
{
_exceptions.Add(ex);
}
return numberOfRecordsAffected;
}
}
You need to look up "seperation of concerns". Its really bad to mix your UI code with you Database Access Layer (DAL). Better to bind the UI to business objects that are populated via a DAL.
To let the UI know about an error you could simply use a delegate.
namespace OperationErrorDelegate
{
public delegate void OperationErrorHandler(Exception ex);
public class DAL
{
public event OperationErrorHandler ReportError;
public void DoDALOperationThatCausesError()
{
try
{
int i = 1;
int j = 0;
int k = i/j;
}
catch (Exception ex)
{
ReportError(ex);
}
}
}
}
Add this code to the form:
using System ;
using System.Windows.Forms;
namespace OperationErrorDelegate
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
DAL DAL = new DAL();
DAL.ReportError += new OperationErrorHandler(DAL_OperationErrorProgress);
DAL.DoDALOperationThatCausesError();
}
private void DAL_OperationErrorProgress(Exception ex)
{
label1.Text = ex.Message;
}
}
}
Assuming the OP's requirement is to display an error message in a label, when the credentials are wrong:
private void btn_login_Click(object sender, EventArgs e)
{
MySqlConnection con = new MySqlConnection("server=localhost;uid=root;password=abc;database=mydb");
MySqlCommand cmd = new MySqlCommand("select * from emp where name='" + textBox1.Text + "'and pwd='" + textBox2.Text + "'",con);
con.Open();
MySqlDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{ //successful
//navigate to next page or whatever you want
}
else
Label1.Text("Invalid userid or password");
con.Close();
}
And if you need error message for wrong data type (the user input string but the database column is Integer), then use validations at client side. You dont need to do it at backend, since that will be a burden.
You can use regular expressions for that in the button_click itself.

Categories