C# delegates problem - c#

I am getting the following error from my C# Windows Application:
Error 1 No overload for 'CreateLabelInPanel' matches delegate 'WorksOrderStore.ProcessDbConnDetailsDelegate' H:\c\WorksOrderFactory\WorksOrderFactory\WorksOrderClient.cs 43 39 WorksOrderFactory
I have 3 .cs files that essentially:
Opens a windows
Has an option for the users to connect to a db
When that is selected, the system will go off and connect to the db, and load some data in (just test data for now)
Then using a delegate, the system should do soemthing, which for testing will be to create a label. However I haven't coded this part yet.
But I can't build until I get this error sorted.
The 3 fiels are called:
WorksOrderClient.cs (which is the MAIN)
WorksOrderStore.cs
LoginBox.cs
Here's the code for each file:
WorksOrderClient.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;
using WorksOrderStore;
namespace WorksOrderFactory
{
using WorksOrderStore;
public partial class WorksOrderClient : Form
{
LoginBox lb = new LoginBox();
private static WorksOrderDB wodb = new WorksOrderDB();
private static int num_conns = 0;
public WorksOrderClient()
{
InitializeComponent();
}
private void connectToADBToolStripMenuItem_Click(object sender, EventArgs e)
{
lb.ShowDialog();
lb.Visible = true;
}
public static bool createDBConnDetObj(string username, string password, string database)
{
// increase the number of connections
num_conns = num_conns + 1;
// create the connection object
wodb.AddDbConnDetails(username, password, database, num_conns);
// create a new delegate object associated with the static
// method WorksOrderClient.createLabelInPanel
wodb.ProcessDbConnDetails(new ProcessDbConnDetailsDelegate(CreateLabelInPanel));
return true;
}
static void CreateLabelInPanel(DbConnDetails dbcd)
{
Console.Write("hellO");
string tmp = (string)dbcd.username;
//Console.Write(tmp);
}
private void WorksOrderClient_Load(object sender, EventArgs e)
{
}
}
}
WorksOrderStore.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WorksOrderFactory;
namespace WorksOrderStore
{
using System.Collections;
// Describes a book in the book list:
public struct WorksOrder
{
public string contractor_code { get; set; } // contractor ID
public string email_address { get; set; } // contractors email address
public string date_issued { get; set; } // date the works order was issued
public string wo_ref { get; set; } // works order ref
public string status { get; set; } // status ... not used
public job_status js { get; set; } // status of this worksorder within this system
public WorksOrder(string contractor_code, string email_address, string date_issued, string wo_ref) : this()
{
this.contractor_code = contractor_code;
this.email_address = email_address;
this.date_issued = date_issued;
this.wo_ref = wo_ref;
this.js = job_status.Pending;
}
}
// Declare a delegate type for processing a WorksOrder:
//public delegate void ProcessWorksOrderDelegate(WorksOrder worksorder);
// Maintains a worksorder database.
public class WorksOrderDB
{
// List of all worksorders in the database:
ArrayList list = new ArrayList();
// Add a worksorder to the database:
public void AddWorksOrder(string contractor_code, string email_address, string date_issued, string wo_ref)
{
list.Add(new WorksOrder(contractor_code, email_address, date_issued, wo_ref));
}
// Call a passed-in delegate on each pending works order to process it:
/*public void ProcessPendingWorksOrders(ProcessWorksOrderDelegate processWorksOrder)
{
foreach (WorksOrder wo in list)
{
if (wo.js.Equals(job_status.Pending))
// Calling the delegate:
processWorksOrder(wo);
}
}*/
// Add a DbConnDetails to the database:
public void AddDbConnDetails(string username, string password, string database, int conn_num)
{
list.Add(new DbConnDetails(username, password, database, conn_num));
}
// Call a passed-in delegate on each dbconndet to process it:
public void ProcessDbConnDetails(ProcessDbConnDetailsDelegate processDBConnDetails)
{
foreach (DbConnDetails wo in list)
{
processDBConnDetails(wo);
}
}
}
// statuses for worksorders in this system
public enum job_status
{
Pending,
InProgress,
Completed
}
public struct DbConnDetails
{
public string username { get; set; } // username
public string password { get; set; } // password
public string database { get; set; } // database
public int conn_num { get; set; } // this objects connection number.
public ArrayList woList { get; set; } // list of works orders for this connection
// this constructor just sets the db connection details
// the woList array will get created later .. not a lot later but a bit.
public DbConnDetails(string username, string password, string database, int conn_num) : this()
{
this.username = username;
this.password = password;
this.database = database;
this.conn_num = conn_num;
woList = new ArrayList();
}
}
// Declare a delegate type for processing a DbConnDetails:
public delegate void ProcessDbConnDetailsDelegate(DbConnDetails dbConnDetails);
}
LoginBox.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WorksOrderFactory
{
public partial class LoginBox : Form
{
public LoginBox()
{
InitializeComponent();
}
private void LoginBox_Load(object sender, EventArgs e)
{
this.Visible = true;
this.Show();
//usernameText.Text = "Username";
//new Font(usernameText.Font, FontStyle.Italic);
}
private void cancelBtn_Click(object sender, EventArgs e)
{
this.Close();
}
private void loginBtn_Click(object sender, EventArgs e)
{
// set up a connection details object.
bool success = WorksOrderClient.createDBConnDetObj(usernameText.Text, passwordText.Text, databaseText.Text);
}
private void LoginBox_Load_1(object sender, EventArgs e)
{
}
}
}
Any ideas??
Cheers,
m

The one thing jumps out when comparing the definition of the delegate with the definition of the method you're trying to use:
static void CreateLabelInPanel(DbConnDetails dbcd)
public delegate void ProcessDbConnDetailsDelegate(DbConnDetails dbConnDetails)
CreateLabelInPanel should probably not be declared as static.

The compiler is just saying that the method you are providing to a delegate is not matching the signature expected by the delegate.
So, in your case.
//To get this line working...
wodb.ProcessDbConnDetails(new ProcessDbConnDetailsDelegate(SomeMethod1));
//The method signature should be like this.
static void SomeMethod1(DbConnDetails dbcd)
//OR even this -- Instance/Static methods can be supplied to same delegate.
void SomeInstanceMethod(DbConnDetails dbcd)..
And if not, the compiler would complain.
Also, by any chance, do you have two classes with the name "DbConnDetails" ???
My best guess is you are referring to "DbConnDetails" that lies in different namespace than the one expected by the delegate.

thanks #amby and #massif and anyone else I may have missed.
This was a school boy error.
It turns out I had another file (which I thought I'd deleted) that also contained a class and constructor called DbConnDetails. I did a search for DbConnDetails in the solution.
I renamed that class/constructor and the filename as well, to be safe.
I then declared
static void CreateLabelInPanel(DbConnDetails dbcd)
which means that the app now compiles/builds again.
Thanks again to everyone.

Related

(UNITY) My JSON file is not loading on start

I am making a basic shop system includes car name, price and buyable. I am saving data to a text file. When I replay, I can't get the last variables I've changed. But, if I refresh at Editor by CTRL+R and start the game, variables are loading correct. What am I doing wrong? I am new at storage and JSON issues. Thanks for answers...
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;
public class GameHandler : MonoBehaviour
{
[Serializable]
public class Car
{
public string name;
public int price;
public bool unlocked;
}
[Serializable]
public class CarList{
public Car[] cars;
}
private Car cars = new Car();
public CarList myCars = new CarList();
//-------
public int chosenCar;
//-------
public TextAsset CARS;
//-------
private void Start() {
GetFromJSON();
}
private void Update() {
if(Input.GetKeyDown(KeyCode.L))
GetFromJSON();
if(Input.GetKeyDown(KeyCode.S))
SaveToJSON();
}
public void ChangeCarIndex(int a){
chosenCar = a;
}
//This is a button func.
public void ChangePrice(int a){
myCars.cars[chosenCar].price = a;
SaveToJSON();
}
public void GetCarName(){
Debug.Log(myCars.cars[chosenCar].name);
}
public void GetCarPrice(){
Debug.Log(myCars.cars[chosenCar].price);
}
public void SaveToJSON(){
string jsOutput = JsonUtility.ToJson(myCars);
File.WriteAllText(Application.dataPath + "/CARS.txt", jsOutput);
Debug.Log("SaveToJSON() called");
}
public void GetFromJSON(){
myCars = JsonUtility.FromJson<CarList>(CARS.text);
Debug.Log("GetFromJSON() called");
}
}
When running this in the editor try to add
public void SaveToJSON()
{
string jsOutput = JsonUtility.ToJson(myCars);
File.WriteAllText(Application.dataPath + "/CARS.txt", jsOutput);
Debug.Log("SaveToJSON() called");
#if UNITY_EDITOR
UnityEditor.AssetDatabase.Refresh();
#endif
}
Though actually this isn't really necessary! Afaik you could also simply set the text of the textasset:
public void SaveToJSON()
{
string jsOutput = JsonUtility.ToJson(myCars);
CARS.text = jsOutput;
Debug.Log("SaveToJSON() called");
}
BUT NOTE:
in general note that this makes only sense in the editor itself.
If you target to do this in an actually later built application you would rather go via a file in Application.persistentDataPath. Problem with that though: The data can easily be seen and edited by the user. So if this is anything sensitive you will need to go for a central database server with user login.

Using OpenFileDialog and StreamReader

There are two classes, one to cover the form (class 1) and the other to cover what gets displayed on the form (class 2). I'm trying to call a method in class 1 from class 2 to display certain information in a text box. I keep getting the error:
An object reference is required for the non-static field, method, or property
I've encountered this error before and been able to make it through, but nothing I've attempted so far has helped in this instance. I'm posting code for both the classes.
Class 1:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
namespace Project6
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
Stream myStream = null;
//Create an instance of the open file dialog box
OpenFileDialog ofd = new OpenFileDialog();
//Set parameters, filter options, and filter index
ofd.InitialDirectory = "c:\\";
ofd.Filter = "Text Files (.txt)|*.txt";
ofd.FilterIndex = 2;
ofd.Multiselect = false;
if (ofd.ShowDialog() == DialogResult.OK)
{
try
{
if ((myStream = ofd.OpenFile()) != null)
{
using (myStream = ofd.OpenFile())
{
StreamReader reader = new StreamReader(myStream);
string studentInformation = "";
string[] studentInformationArray = new string[11];
studentInformation = reader.ReadLine();
while ((studentInformation = reader.ReadLine()) != null)
{
studentInformationArray = studentInformation.Split(',');
Student newStudent = new Student(studentInformationArray);
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
textBox1.Text = Student.GetName(); //This generates the compiler error
textBox1.Select(6, 5);
MessageBox.Show(textBox1.SelectedText);
}
}
}
Class 2:
using System;
using System.Windows.Forms;
namespace Project6
{
class Student
{
//Initialize variables
private string[] studentInformationArray;
//Constructor that accepts the studentInformationArray as an argument
public Student(string[] studentInformationArray)
{
this.studentInformationArray = studentInformationArray;
}
public Student()
{
string className = studentInformationArray[1];
string semester = studentInformationArray[2];
string picture = studentInformationArray[3];
int project1 = Convert.ToInt32(studentInformationArray[4]);
int project2 = Convert.ToInt32(studentInformationArray[5]);
int project3 = Convert.ToInt32(studentInformationArray[6]);
int project4 = Convert.ToInt32(studentInformationArray[7]);
int project5 = Convert.ToInt32(studentInformationArray[8]);
int project6 = Convert.ToInt32(studentInformationArray[9]);
int midtermExam = Convert.ToInt32(studentInformationArray[10]);
int finalExam = Convert.ToInt32(studentInformationArray[11]);
}
public string GetName()
{
string studentName;
studentName = studentInformationArray[0];
return studentName;
}
}
}
That's because that's not how you use the OpenFileDialog. Take a look at this example hosted by the MSDN here:
Edit: answering to your edited question. You will always get a NullReferenceException in the Student() constructor because you are never assigning something to your studentInformationArray. So you can fix it like this:
public Student()
{
studentInformationArray = new studentInformationArray[12];
string className = studentInformationArray[1];
// rest of your code...
}
However, you should take into account that studentInformationArray will be an empty array unless you assign something to it. Since you have a Student() overload that takes a string[], I'd suggest you that you either remove the default constructor or make it call the overloaded with default information, like this:
public Student(string[] studentInformationArray)
{
string className = studentInformationArray[1];
// rest of your code...
int project1 = int.Parse(studentInformationArray[4]); // always prefer int.Parse() instead of Convert.ToInt32()
// rest of your code...
this.studentInformationArray = studentInformationArray;
}
public Student()
{
string[] defaultInformation = new string[12];
// add information
defaultInformation[0] = "some information";
// ...
new Student(defaultInformation);
}
Some more points to take into account:
Class-level fields/properties should be spelled in Pascal Case (first letter of each word in uppercase, rest in lowercase)
Try to never use this.variableName = variableName.
Variables names should never include the type of the variable, that's redundant.
So, for example, change this:
private string[] studentInformationArray;
for this:
private string[] StudentInformation;
Answering your last question, regarding the compiler error, you need a reference to the Student read in order to get its name. You could do something like this:
public partial class Form1 : Form
{
private Student StudentRead;
// rest of your code...
// from your read method:
StudentRead = new Student(studentInformationArray);
// and finally:
private void textBox1_TextChanged(object sender, EventArgs e)
{
textBox1.Text = StudentRead.GetName();

Checking a Property of an Object In a Queue

I need to compare a name of an object (test) with the name of a test that has been placed into a queue. The logic I have is to use a foreach loop so that for each test in the queue I can compare the name that the user provides with the name on each test until it finds a match (in which it will tell the user the score they made on the test in a message box).
The code in the snippet is incomplete; using submittedTests with a getter doesn't work (doesn't give me an option to do so in intellisense).
This takes place in the btnFindTest_Click method. This is the code that I have so far:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ConsoleApplication1
{
public partial class Form1 : Form
{
//Stack and Queue calls
Queue submittedTest = new Queue();
Stack outForChecking = new Stack();
public Form1()
{
InitializeComponent();
}
private void btnSubmitTest_Click(object sender, EventArgs e)
{
//generates a random test score
Random rdm = new Random();
int testScore = rdm.Next(0, 100);
string score = testScore.ToString();
//assigns user input to a variable
string name = txtName.Text;
//Generate a new test that passes in
Test tests = new Test(name, score);
//shows the user the name they just enetered
label3.Text = String.Format("{0}", name);
//adds submitted test to the queue, then displays that test in a list box
submittedTest.Enqueue(tests);
listSubTests.Items.Add(new Test(name, score));
//Clears input box for next user input
txtName.Clear();
}
private void btnFindTest_Click(object sender, EventArgs e)
{
string compareName = "";
string tempName = txtName.Text;
foreach (Test tests in submittedTest)
{
if (compareName == tempName)
{
System.Windows.Forms.MessageBox.Show("Your score was --");
}
}
}
public void txtName_TextChanged(object sender, EventArgs e)
{
}
private void txtScore_TextChanged(object sender, EventArgs e)
{
}
private void btnExit_Click(object sender, EventArgs e)
{
Close();
}
}
}
And the test object is defined in it's own class here
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Test
{
private string name;
private string score;
public string Name
{
get { return name; }
set { name = value; }
}
public string Score
{
get { return score; }
set { score = value; }
}
public Test(string name, string score)
{
this.name = name;
this.score = score;
}
public override string ToString()
{
return (String.Format("{0} {1} ", name, score));
}
}
}
I'm reletively new to C# and this project is for school, so if I'm far off, please let me know!
Based on your example, you may have forgotten to use the object:
foreach (Test tests in submittedTest)
{
if (tests.Name == tempName)
{
System.Windows.Forms.MessageBox.Show("Your score was --");
}
}

Update a value in treeListView in objectListView

I have built a treeListView:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TreeListViewTest1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.treeListView1.CanExpandGetter = delegate(object x)
{
return true;
};
this.treeListView1.ChildrenGetter = delegate(object x)
{
Contract contract = x as Contract;
return contrat.Children;
};
column1.AspectGetter = delegate(object x)
{
if(x is Contract)
{
return ((Contract)x).Name;
}
else
{
return " ";
}
};
column2.AspectGetter = delegate(object x)
{
if(x is Contract)
{
return ((Contract)x).Value;
}
else
{
Double d = (Double)x;
return d.ToString();
}
};
this.treeListView1.AddObject(new Contract("A", 1));
}
private void treeListView1_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
public class Contract
{
public string Name { get; set;}
public Double Value { get; set; }
public List<Double> Children {get; set;}
public Contract(string name, Double value)
{
Name = name;
Value = value;
Children = new List<Double>();
Children.Add(2);
Children.Add(3);
}
}
}
It gives this output:
Name Value
A 1
2
3
How do I update the values of column2 ("Value") of the parent and the children from within an event? (increasing each value by of the parent and the children.)
private void button1_Click(object sender, EventArgs e)
{
}
I do not understand if I have to use the AspectGetter again or can i modify just the values in column2 somehow and then refreshObjects().
I do not understand if I have to use the AspectGetter again or can i modify just the values in column2 somehow and then refreshObjects().
No, you should just manipulate the underlying model object and call treeListView1.RefreshObject(myObject); for example, where myObject should be a Contract in you case. This will refresh the contents of the respective rows.
I don't know what your button1_Click() is supposed to do, but you obviously require a reference of the object you want to refresh. This could be the currently selected object for example (treeListView.SelectedObject). If you tell what you want to do, I may be able to give you more information.

TextBox not updating in C#

Specifically looking at the arrive method in the Customer class. I am using a for loop to create instances of the customer class, and when I try to write out their arrival times to a textBox (Just for testing purposes) the text box does not update. Why is this?
This is just a small simulation project for my Computing class. It is in its early stages, and is probably wrong in a lot of places!
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;
using System.Threading;
namespace QueueSimulation
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void Form1_Load(object sender, EventArgs e)
{
MessageBox.Show("The form has loaded");
}
public void goButton_Click(object sender, EventArgs e)
{
Initialisers init = new Initialisers();
Customer customer = new Customer();
customer.Arrive();
}
private void stopButton_Click(object sender, EventArgs e)
{
// put code here to break out of the program
}
}
public class Customer : Initialisers
{
int waitingTime;
int arrivalTime;
int arrivalInterval;
Initialisers init = new Initialisers();
public void Arrive()
{
Customer[] customer = new Customer[1000];
int counter = 0;
for (int i = 1; i <= 10; i++)
{
customer[i] = new Customer();
customer[i].TimeArrived();
displayArrival.Text = displayArrival.Text + customer[i].TimeArrived().ToString();
// Implement something to either show the time in the queue if needed
Thread.Sleep(init.CustomerArriveTime*100);
}
MessageBox.Show("All of the customers have arrived");
}
public string TimeArrived()
{
return Convert.ToString(DateTime.Now);
}
public void Leave()
{
}
public void GetServed()
{
}
}
public class Server
{
bool servingStatus;
int servingTime;
public void Serve()
{
}
}
public class Initialisers : Form1
{
private int cust_no = 3;
public int CustomerArriveTime
{
get
{
return cust_no;
}
set
{
cust_no = value;
}
}
private int s_time = 4;
public int serveTime
{
get
{
return s_time;
}
set
{
s_time = value;
}
}
}
}
Pass to the Arrive the instance of the textbox object created on your Form1.
public void Arrive(TextBox displayArrival)
Why are you inheriting the Form1 in Initialiserz? It's better to pass the reference to Form1 instead of inheritance in this case.
This seems overly complex. Try to model the real world. What is Initialisers, and why do you have an inheritance tree: Customer > Initialisers > Form1?
You're customer is writing to its own TextBox, instead of the TextBox you're looking at (the one from the Form that is visible).
Why not have a method Arrive that sets a private field to DateTime.Now. Then, ask the Customer its TimeArrived, which returns this field. In your Form, call these methods as much as needed in your loop.
This also seperaties command (Arrive) from query (TimeArrived) + keeps your inheritance more logical.
You might not even need Initialisers anymore. And don't let Customer inherit from Form, because a Customer isn't a Form.
I think there is more of a design issue here, you are creating instances of customer inside customer.
Your customer Arrive method should probably be a function inside the another class, like below, customer should just define what a customer is. Processing them should be handled by a different class.
class Customer
{
int waitingTime;
int arrivalTime;
int arrivalInterval;
// etc...
}
class ProcessCustomers
{
pubic void Arrive()
{
// etc...
}
}
public void goButton_Click(object sender, EventArgs e)
{
Initialisers init = new Initialisers();
ProcessCustomers CustomerQueue = new ProcessCustomers();
CustomerQueue .Arrive();
}
But for the text box issue you will have to expose a property in the form class and set it like that,
string ArrivalTime
{
get
{
return textBox1.Text;
}
set
{
textBox1.Text = value;
}
}

Categories