Using OpenFileDialog and StreamReader - c#

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();

Related

C# error CS0103 when using methods in different classes

I'm a newbie in C# and not native English (sorry for that); I am using Visual Studio 2017 using WinForm application.
To test some features to be added in an already existing project, I have created a new Winform application. This simple software writes and reads strings to and from a file. So, in the form I have 2 textboxes and 3 buttons: Save to file, Read from file and Update. To reduce the confusion in the bigger project, I've decided to split the methods in different classes: each one does one job and the form script has the minimum quantity of code possible.
The 3 .cs files (clases) are:
The form partial class,
SaveFile class, where the job to save the string to a text file is carried out,
OpenFile class, where the job to read the text file returning the lines in a list of strings.
All the 3 classes have been created and added to the project ProvaSalvataggioFile2.
So, the form class is (take note only of the methods' name, I have written all the code for completeness, if someone wants to test the code)
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace ProvaSalvataggioFile2
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void btnSave_Click(object sender, EventArgs e)
{
string inputString = tbInputText.Text;
if (inputString.IsValidString())
{
inputString.SaveToFile();
}
else
{
MessageBox.Show("The input string is not valid: please insert a valid string",
"Empty or null input string",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
tbInputText.Focus();
}
}
private void btnOpenFile_Click(object sender, EventArgs e)
{
List<string> textFileContent = new List<string>();
textFileContent = OpenTextFile();
tbFileText.Text = string.Join(Environment.NewLine, textFileContent);
}
private void btnUpdate_Click(object sender, EventArgs e)
{
if (File.Exists(fileName))
{
List<string> textReadFromFile = new List<string>();
textReadFromFile = File.ReadAllLines(fileName).ToList();
tbFileText.Text = string.Join(Environment.NewLine, textReadFromFile);
}
}
}
}
The SaveFile class is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace ProvaSalvataggioFile2
{
public static class SaveFile
{
public static bool IsValidString(this string stringToValidate)
{
bool result = true;
if (string.IsNullOrEmpty(stringToValidate))
{
result = false;
}
return result;
}
public static bool SaveToFile(this string stringToSave)
{
bool result = true;
//bool savedfile;
DialogResult messageBoxResult;
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
//saveFileDialog1.InitialDirectory = #"C:\";
saveFileDialog1.Title = "Save text Files";
saveFileDialog1.CheckFileExists = false;
saveFileDialog1.OverwritePrompt = false;
saveFileDialog1.CheckPathExists = true;
saveFileDialog1.DefaultExt = "txt";
saveFileDialog1.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
saveFileDialog1.FilterIndex = 1;
saveFileDialog1.RestoreDirectory = true;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
if (File.Exists(saveFileDialog1.FileName))
{
messageBoxResult = MessageBox.Show("The file is already existing: do you want:\n\t\u22c5OVERWRITE the file [YES]\n\t\u22c5APPEND data in the file [NO]\n\t\u22c5Use another file [CANCEL]",
"Overwrite file",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Asterisk,
MessageBoxDefaultButton.Button3);
if (messageBoxResult == DialogResult.Yes)
{
messageBoxResult = MessageBox.Show(("Are you sure to overwrite the file in\n" + saveFileDialog1.FileName),
"Sure to overwrite file?",
MessageBoxButtons.OKCancel);
if (messageBoxResult == DialogResult.OK)
{
try
{
File.WriteAllText(saveFileDialog1.FileName, stringToSave);
result = true;
}
catch
{
result = false;
}
}
}
else if (messageBoxResult == DialogResult.No)
{
//MessageBox.Show(("Message to save: \"" + stringToSave + "\"\nin \"" + saveFileDialog1.FileName));
try
{
File.AppendAllText(saveFileDialog1.FileName, (Environment.NewLine + stringToSave));
result = true;
}
catch
{
result = false;
}
}
else
{
messageBoxResult = MessageBox.Show("Please enter a new filename",
"Save in a new file",
MessageBoxButtons.OKCancel);
if (messageBoxResult == DialogResult.OK)
{
stringToSave.SaveToFile();
}
}
}
else
{
File.WriteAllText(saveFileDialog1.FileName, stringToSave);
result = true;
}
}
return result;
}
}
}
And the OpenFile class is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace ProvaSalvataggioFile2
{
public class OpenFile
{
public string fileName { get; set; }
public List<string> OpenTextFile()
{
List<string> textReadFromFile = new List<string>();
//textReadFromFile = new List<string>();
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.CheckPathExists = true;
openFileDialog1.CheckFileExists = true;
openFileDialog1.RestoreDirectory = true;
openFileDialog1.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
openFileDialog1.FilterIndex = 1;
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
fileName = openFileDialog1.FileName.ToString();
textReadFromFile = File.ReadAllLines(openFileDialog1.FileName).ToList();
}
return textReadFromFile;
}
}
}
Now, if I put all the methods in the form class, all works just fine, with no problems (the application is stupid, only made to test the logic behind). But if I split the code in the 3 classes, I have:
Error CS0103 The name 'OpenTextFile' does not exists in the current context ProvaSalvataggioFile2 Form1.cs 41
Error CS0103 The name 'fileName' does not exists in the current context ProvaSalvataggioFile2 Form1.cs 47
Error CS0103 The name 'fileName' does not exists in the current context ProvaSalvataggioFile2 Form1.cs 50
So there must be some problem related with the splitting in classes. I have tried googling the error, but it seems that this error comes out in very different occasions and for different reasons (nothing in common with mine). I argue that I have missed something in the process of adding the new class or in the code defining the class.
I repeat myself, if I copy and paste the methods in the form class, the application works perfectly, but the same methods put in a separate class (but in the same file of the form class) doesn't.
The problem here is that you are trying to access members of the OpenFile class within the MainForm class. Initialize an instance of OpenFile and keep it in a variable within your MainClass to reuse
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace ProvaSalvataggioFile2
{
public partial class MainForm : Form
{
// Initialize OpenFile
private readonly OpenFile openFile = new OpenFile();
public MainForm()
{
InitializeComponent();
}
private void btnSave_Click(object sender, EventArgs e)
{
string inputString = tbInputText.Text;
if (inputString.IsValidString())
{
inputString.SaveToFile();
}
else
{
MessageBox.Show("The input string is not valid: please insert a valid string",
"Empty or null input string",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
tbInputText.Focus();
}
}
private void btnOpenFile_Click(object sender, EventArgs e)
{
List<string> textFileContent = new List<string>();
textFileContent = openFile.OpenTextFile(); // Open Text File via openFile variable
tbFileText.Text = string.Join(Environment.NewLine, textFileContent);
}
private void btnUpdate_Click(object sender, EventArgs e)
{
if (File.Exists(openFile.fileName)) // Validate file exists via openFile.fileName property
{
List<string> textReadFromFile = new List<string>();
textReadFromFile = File.ReadAllLines(fileName).ToList();
tbFileText.Text = string.Join(Environment.NewLine, textReadFromFile);
}
}
}
}
You can also reduce your code by changing your IsValidString method to an extension method
public static bool IsValidString(this string stringToValidate) => !string.IsNullOrEmpty(stringToValidate)
I would recommend somewhat redesigning the code because there are potential bugs waiting to be found by using one class, I.E OpenFile, for opening and checking file contents. What if the file isn't opened and fileName is an empty string for example.
See the following MSDN article on classes to understand them more in-depth, and how the interact with each other.
Refactored Code
I have refactored the code to make it a bit more manageable and readable, please see below.
Here's a new class called TextFile which you can store the filename and contents in.
namespace ProvaSalvataggioFile2
{
public class TextFile
{
public TextFile(string fileName, string contents)
{
FileName = fileName;
Contents = contents;
}
public string FileName { get; set; }
public string Contents { get; set; }
}
}
Your OpenFile class is actually named pretty well, it has quite a good separation of concerns - meaning that on first glance I can see that it's a class which should only be used to open files, though you could go a step further and abstract the UI code away which couples you to Win Forms. OpenTextFile now returns a TextFile object
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace ProvaSalvataggioFile2
{
public class OpenFile
{
public TextFile OpenTextFile()
{
TextFile textFile;
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.CheckPathExists = true;
openFileDialog1.CheckFileExists = true;
openFileDialog1.RestoreDirectory = true;
openFileDialog1.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
openFileDialog1.FilterIndex = 1;
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
string fileName = openFileDialog1.FileName.ToString();
string textReadFromFile = File.ReadAllText(openFileDialog1.FileName);
textFile = new TextFile(fileName, textReadFromFile);
}
return textFile;
}
}
}
And of course, MainForm has to be updated to take the new object into consideration, I've removed duplicated code, reused your OpenFile class and introduced a RefreshTextFile method for setting the label text - this time you don't have to worry about file names being valid.
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace ProvaSalvataggioFile2
{
public partial class MainForm : Form
{
private readonly OpenFile openFile = new OpenFile();
public MainForm()
{
InitializeComponent();
}
private void btnSave_Click(object sender, EventArgs e)
{
string inputString = tbInputText.Text;
if (inputString.IsValidString())
{
inputString.SaveToFile();
}
else
{
MessageBox.Show("The input string is not valid: please insert a valid string",
"Empty or null input string",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
tbInputText.Focus();
}
}
private void btnOpenFile_Click(object sender, EventArgs e)
{
RefreshTextFile();
}
private void btnUpdate_Click(object sender, EventArgs e)
{
RefreshTextFile();
}
private void RefreshTextFile()
{
TextFile textFile = openFile.OpenTextFile();
tbFileText.Text = textFile?.Contents;
}
}
}
Please note I have refactored this using Notepad++ and haven't put it through a compiler.
Your Form class doesn't know where or what OpenTextFile() is, same goes for fileName.
You need to create an instance of the object you want to use.
Try adding this code to MainForm:
private OpenFile _openFile;
public MainForm()
{
this._openFile = new OpenFile();
InitializeComponent();
}
This creates a new instance of the OpenFile class that MainForm can now use.
You can also make OpenFile static but that is not considered to be a best practice.
Please note that since your OpenFile.fileName is not initialized that you might want to add something like this as well.
public OpenFile(string initialFileName = "defaultFilename"){
this.fileName = initialFileName;
}
you can then even specify the filename in MainForm by providing it as an argument.
Or if you don't want to set an argument you can do a null check before reading/using the fileName.
for more info about objects and constructor see:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/objects
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors

Phone list c# (Reading from a file)

This is a pretty simple program. It IS a homework project. The program should start, read a .txt file, populate the name list and when you click on the name, the phone number is displayed. I have it coded, no errors, no warnings. It will not read the .txt file and I can't figure out why. I've been scouring my book, youtube, even here, but can't pin it down. Any help would be appreciated. Here is my current code.
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;
using System.IO;
namespace Phonebook
{
struct PhoneBookEntry
{
public string name;
public string phone;
}
public partial class Form1 : Form
{
// FIeld to hold a list of PhoneBookEntry objects.
private List<PhoneBookEntry> phoneList = new List<PhoneBookEntry>();
public Form1()
{
InitializeComponent();
}
// The ReadFile method reads the contents of the
//PhoneList.txt file and tores it as PhoneBokeEntry
// objects in the phoneList.
private void ReadFile()
{
try
{
StreamReader inputFile; // To read the file
string line; // To hold a line from the file
// Create an instance of the PhoneBookEntry structure.
PhoneBookEntry entry = new PhoneBookEntry();
// Create a delimiter array.
char[] delim = { ',' };
// Open the PhoneList file.
inputFile = File.OpenText("PhoneList.txt");
// Read the lines from the file.
while (!inputFile.EndOfStream)
{
// Read a line from the file.
line = inputFile.ReadLine();
// Tokenize the line
string[] tokens = line.Split(delim);
// Store the tokens in the entry object.
entry.name = tokens[0];
entry.phone = tokens[1];
// Add the entry object to the List.
phoneList.Add(entry);
}
}
catch (Exception ex)
{
// Display an error message.
MessageBox.Show(ex.Message);
}
}
// The DisplayNames method displays the list of names
// in the namesListBox conrol.
private void DisplayNames()
{
foreach (PhoneBookEntry entry in phoneList)
{
nameListBox.Items.Add(entry.name);
}
}
private void Form1_Load(object sender, EventArgs e)
{
// Read the PhoneList.txt file.
ReadFile();
// DIsplay the names.
DisplayNames();
}
private void nameListBox_SelectedIndexChanged(object sender, EventArgs e)
{
// Get the index of the selected item.
int index = nameListBox.SelectedIndex;
// Display the corresponding phone number.
phoneLabel.Text = phoneList[index].phone;
}
private void exitButton_Click(object sender, EventArgs e)
{
// close the form.
this.Close();
}
private void Form1_Load_1(object sender, EventArgs e)
{
}
}
}

Sorting data from file in order from StreamReader

I have a windows form that uses a StreamReader to read form data into some text boxes. That works perfectly fine. The problem now is that I want to display the data from the file in order alphabetically by names. Early I tried an array.Sort method, by it didn't work so well.
Here is my code:
Note: I close the reader and file in the dispose method.
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;
using System.IO;
namespace ViewArchives
{
public partial class Form1 : Form
{
const char DELIM = ',';
const string FILENAME = #"F:\lscSpring2016\CIS2620\FinalProject\TicketMaster\bin\Debug\SoldTickets.txt";
string recordIn;
string[] fields;
static FileStream file = new FileStream(FILENAME, FileMode.Open, FileAccess.Read);
StreamReader reader = new StreamReader(file);
public Form1()
{
InitializeComponent();
}
private void btnView_Click(object sender, EventArgs e)
{
try
{
recordIn = reader.ReadLine();
fields = recordIn.Split(DELIM);
nameBox.Text = fields[0];
ticketsBox.Text = fields[1];
purchaseBox.Text = fields[2];
dateBox.Text = fields[3];
}
catch (NullReferenceException)
{
label5.Text = "You have viewed\nall the records filed.";
btnView.Enabled = false;
}
}
}
}
There is a simpler way.
First, introduce a class for containing data from a single line:
class Record
{
public string Name { get; set; }
public string Tickets { get; set; }
public string Purchase { get; set; }
public string Date { get; set; }
}
In your Form1 class do the followings:
Create two fields.
One for the record list and one for indicating the current index in the record collection.
Record[] soldTickets; // This will contain the file data
int currentRecordIndex = -1;
Create a method that loads the whole file in one step into the record collection:
private void LoadRecords()
{
soldTickets =
File
.ReadAllLines(FILENAME)
.Select(line =>
{
string[] data = line.Split(DELIM);
return
new Record()
{
Name = data[0],
Tickets = data[1],
Purchase = data[2],
Date = data[3]
};
})
.OrderBy(record => record.Name)
.ToArray();
currentRecordIndex = -1;
}
Then your button click event handler can look like this:
private void btnView_Click(object sender, EventArgs e)
{
Record currentRecord = soldTickets.ElementAtOrDefault(++currentRecordIndex);
if (currentRecord == null)
{
label5.Text = "You have viewed\nall the records filed.";
btnView.Enabled = false;
return;
}
nameBox.Text = currentRecord.Name;
ticketsBox.Text = currentRecord.Tickets;
purchaseBox.Text = currentRecord.Purchase;
dateBox.Text = currentRecord.Date;
}

Trying to read a text file into classes then cycle through

Hi am a fairly novice when it comes to c# and I have being trying to read out a text file then splitting it into sections with classes but have trouble with where to declare them an then how to cycle through the records. here's my code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;
using System.Windows.Forms;
namespace Assignment_3
{
public partial class Form1 : Form
{
string s;
string ss;
int i = 1;
string infilename;
int num;
SortedList sList = new SortedList();
int x = 0;
public Form1()
{
InitializeComponent();
student myself = new student();
infilename = "text.txt";
StreamReader sr1 = new StreamReader(infilename);
sList.Clear();
while ((s = sr1.ReadLine()) != null)
{
string[] strs = s.Split(',');
myself.firstname = strs[0];
myself.middlename = strs[1];
myself.surname = strs[2];
myself.dob = DateTime.Parse(strs[3]);
myself.dob.ToString(strs[3]);
myself.sex = strs[4];
ss = myself.dob.ToString("u");
sList.Add(myself.firstname, myself);
}
sr1.Close();
num = sList.Count;
student[] pArray = new student[num];
string[] keys = new string[num];
foreach (DictionaryEntry d in sList)
{
keys[x] = (string)d.Key;
pArray[x] = (student)d.Value;
x++;
}
if (i == 0)
{lblmessage.Text = "Already at the first record."; i = 1; }
if (i == num)
{lblmessage.Text = "Already at the last record.";i = num-1; }
lbllastname.Text = pArray[i].surname;
lblfirstname.Text = pArray[i].firstname;
lblsecondname.Text = pArray[i].middlename;
lbldob.Text = pArray[i].dob.ToString();
lblsex.Text = pArray[i].sex;
}
private void btnlast_Click(object sender, EventArgs e)
{
i = num;
}
private void btnfirst_Click(object sender, EventArgs e)
{
i = 0;
}
private void btnnext_Click(object sender, EventArgs e)
{
i++;
}
private void btnprev_Click(object sender, EventArgs e)
{
i--;
}
}
}
and my class file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Assignment_3
{
class student
{
public string firstname;
public string middlename;
public string surname;
public DateTime dob;
public string sex;
}
}
anyone have any ideas where am going wrong?? I have no errors but find that the text fields do not update with the new record's and then when stepped through the array class holds the correct amount of records and fields, I feel its going to be something very obvious put cant put my finger on it.
Any help would be very appreciated.
You should create new instance of student inside for loop. Because at the moment you have only one instance of student class and all items in SortedList are pointing to same object.

C# delegates problem

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.

Categories