Loading a text file into a listbox - c#

I am trying to load data into a listbox in a windows form application in c#. I have code from my main form which will put the data onto the listbox as followed...
namespace HRApplication
{
public partial class MainForm : Form
{
// The file used to store employee details
string employeesFile = "employees.txt";
// The collection used to hold the employee data
Employees employees;
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
employees = new Employees();
if (!employees.Load(employeesFile))
{
MessageBox.Show("Unable to load employees file");
}
else
{
PopulateListBox();
}
}
private void PopulateListBox()
{
listBoxEmployees.Items.Clear();
foreach (Employee employee in employees)
{
listBoxEmployees.Items.Add(employee.lastName + ", " +
employee.firstName);
}
//listBoxEmployees.SelectedIndex = 0;
}
from this I have a class called Employees where I am trying to get the load method working here is the code I have and any help would be very helpful.
namespace HRApplication
{
public class Employees : List<Employee>
{
public Employees()
{ }
public bool Load(string employeesFile)
{
List<string> lines = new List<string>();
using (StreamReader reader = new StreamReader("employees.txt"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
lines.Add(line);
}
return true;
}
}
}
}

Suppose, for simplicity that your Employee class is something like this.
public class Employee
{
public string lastName {get;set;}
public string firstName {get;set;}
public override string ToString()
{
return lastName + ", " + firstName;
}
}
Now, when you load a line of text from the file you should split it in the parts that represent the employee data. Use that data to create an instance of the employee class and add the instance to the base class of Employees (a List<Employee>)
public bool Load(string employeesFile)
{
using (StreamReader reader = new StreamReader("employees.txt"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// Suppose that your line is splittable using a comma...
string[] temp = line.Split(',');
// This is really simplicistic. In a real world scenario
// you should check if the line contains correctly all the
// fields required to populate an Employee...
Employee emp = new Employee()
{
firstName = temp[0],
lastName=temp[1]
};
// This class is derived from List<T>
// so you can use the Add method
// to add the employee to itself...
Add(emp);
}
return true;
}
}
}
At this point your loop to populate the listbox should work (I use the ToString() overload to hide the building of the text for the ListBox)
private void PopulateListBox()
{
listBoxEmployees.Items.Clear();
foreach (Employee employee in employees)
{
listBoxEmployees.Items.Add(employee);
}
//listBoxEmployees.SelectedIndex = 0;
}

Related

How could I iterate through list of abstract type, containing non-abstract types derived from that abstract class?

I need to iterate through list I created, but can't access objects inside. I tried a few different functions but nothing worked and I'm afraid I'm using the wrong tools for the job.
namespace WholesaleApp
{
internal class Program : Wholesale
{
static string filePath = "C:\\Wholesale.txt";
static void Main(string[] args)
{
List<Merchandise> productList = new List<Merchandise>();
productList = ReadFromFile(filePath);
foreach(Merchandise merchandise in productList)
{
//this is where I'm trying to access objects inside and display them
}
}
}
}
This is my abstract class:
namespace WholesaleApp
{
internal abstract class Merchandise
{
public string merchandiseName { get; set; }
public int merchandiseAmount { get; set; }
public Merchandise(string name, int amount)
{
merchandiseName = name;
merchandiseAmount = amount;
}
}
}
And this is one of the three classes deriving from Merchandise abstract class:
namespace WholesaleApp
{
internal class MerchandiseClothing : Merchandise
{
public string clothSize { get; set; }
public string clothType { get; set; }
public MerchandiseClothing(string _clothType, string _clothSize, string name, int amount) : base(name, amount)
{
clothType = _clothType;
clothSize = _clothSize;
}
public void ReturnAll()
{
Console.Write(merchandiseName+" of type: "+clothSize+" in amount: "+merchandiseAmount+ " and jeep status is: "+clothType);
}
}
}
Finally, my function where I add everything to the final list:
namespace WholesaleApp
{
internal class Wholesale
{
static public List<Merchandise> ReadFromFile(string filePath)
{
List<Merchandise> result = new List<Merchandise>();
string line;
StreamReader reader = null!;
try
{
reader = new StreamReader(filePath);
line = reader.ReadLine()!;
while (line != null)
{
string[] words = line.Split(';');
if (words[0] == "MerchandiseComputer")
{
result.Add(new MerchandiseComputer(words[1], words[2], Int32.Parse(words[3])));
}
else if (words[0] == "MerchandiseCarParts")
{
result.Add(new MerchandiseCarParts(bool.Parse(words[1]), words[3], words[2], Int32.Parse(words[4])));
}
else if (words[0] == "MerchandiseClothing")
{
result.Add(new MerchandiseClothing(words[1], words[2], words[3], Int32.Parse(words[4])));
}
line = reader.ReadLine()!;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
reader.Close();
}
return result;
}
}
}
It should be possible to iterate here iterate through objects already. If you want to use specific fields from each specific class, you can put here a check on type and do whatever you want. For example:
foreach (Merchandise merchandise in productList)
{
if (merchandise is MerchandiseClothing clothing)
{
Console.WriteLine(clothing.clothSize); //Can be use any field from Clothing class
Console.WriteLine(clothing.merchandiseAmount); //And also from parent
}
else if (merchandise is MerchandiseComputer computer)
{
//Do what you want
}
}
However, better to make abstract method like WriteToConsole in Merchandise class and override it in each implementation. Like ReturnAll method in your MerchandiseClothing class

How can I access a string from another class in WPF

I got two scenes (windows), "MainWindow.xaml.cs" and "SecondaryWindow.xaml.cs". I also have one class "Control.cs".
Im trying to declare 2 different List<string>, and 2 public string in my Control.cs class.
It looks like this.
class Control
{
}
public class MyControl
{
List<string> NameList = new List<string>();
List<string> DescriptionList = new List<string>();
public string Name {
get { return Name; }
set { Name = value; }
}
public string Description {
get { return Description; }
set { Description = value; }
}
}
I want to access the different strings from Control.cs in my SecondWindow.xaml.cs class so that i can give them each a value from 2 textboxes in SecondWindow.
After this i want the string Name to save to NameList and string Description to DescriptionList.
Then I will send Name to a ListBox in "MainWindow" where i think it could be added something like this..?
private void Button_SaveAndReturn(object sender, RoutedEventArgs e)
{
var main = (MainWindow)Application.Current.MainWindow;
if (Example.Name != "" && Example.Description != "")
{
DateTime now = DateTime.Now;
main.listBox.Items.Add(string.Format("{0}: {1} ", Example.name, now));
this.Close();
}
Im trying my best to give out as much details as i can, tell me if there is anything else you need! Thanks in advance.
Edit
Here is my Control class:
class Control
{
List<string> NameList = new List<string>();
List<string> DescriptionList = new List<string>();
public static string Name
{
get { return Name; }
set { Name = value; }
}
public static string Description
{
get { return Description; }
set { Description = value; }
}
}
And my main class
private void Button_SaveAndReturn(object sender, RoutedEventArgs e)
{
List<string> nameList = new List<string>();
List<string> descriptionList = new List<string>();
var name = Control.Name;
var desc = Control.Description;
var main = (MainWindow)Application.Current.MainWindow;
if (name != "" && desc !="")
{
nameList.Add(name);
descriptionList.Add(desc);
DateTime now = DateTime.Now;
main.listBox.Items.Add(string.Format("{0}: {1} ", name, now));
this.Close();
}
else if (name== "")
{
MessageBox.Show("Please enter a name", "Name Error", MessageBoxButton.OK, MessageBoxImage.Error);
this.NameInput.Focus();
}
else
{
MessageBox.Show("Please enter some text", "Text Error", MessageBoxButton.OK, MessageBoxImage.Error);
this.TextInput.Focus();
}
Are you using WPF's MVVM capabilities? If you are, you can declare those lists and variables in a viewmodel common to all those classes; otherwise just mark all those properties as static so you can access them from the other classes like: MyControl.Name, MyControl.Description, etc...
I would use Prism for that.
Here is an example:
Class which will raise the event:
public class PublisherClass
{
public void UpdateName(string name)
{
Utility.EventAggregator.GetEvent<UpdateNameEvent>().Publish(name);
}
}
Two classes will subscribe to this event:
public class SubscriberClass1
{
public string Name { get; set; }
public SubscriberClass1()
{
Utility.EventAggregator.GetEvent<UpdateNameEvent>().Subscribe(UpdateName);
}
private void UpdateName(string name)
{
this.Name = name;
}
}
and
public class SubscriberClass2
{
public string Name { get; set; }
public SubscriberClass2()
{
Utility.EventAggregator.GetEvent<UpdateNameEvent>().Subscribe(UpdateName);
}
private void UpdateName(string name)
{
this.Name = name;
}
}
EventAggregator which is part of Prism.Events resides here:
public class Utility
{
public static EventAggregator EventAggregator { get; set; }
static Utility()
{
EventAggregator = new EventAggregator();
}
}
And the event is simply defined like this:
public class UpdateNameEvent : PubSubEvent<string>
{
}
Now give it a try:
static void Main(string[] args)
{
PublisherClass publisher = new PublisherClass();
SubscriberClass1 subscriber1 = new SubscriberClass1();
SubscriberClass2 subscriber2 = new SubscriberClass2();
publisher.UpdateName("Name1");
Console.WriteLine(subscriber1.Name);
Console.WriteLine(subscriber2.Name);
}
For this example i am using a string as parameter but you can replace that according to your needs.
Be it an MVVM approach or any other pattern, you can easily implement this kind of communication.
Install Prism.Core with the help of Nuget and you will get the reference to Prism dll.
That's about it.

c# getting the right form to show

I have two forms a salaried employee and an hourly employee which has the employees details on it loading from a textfile. In my main form there is a listbox with the names of the employees, once one is clicked, i want to be able to press an edit employee details button on my main form and for the correct form to come up and I am struggling on how to do this. The code for my main form is here:
public partial class MainForm : Form
{
// The file used to store employee details
string employeesFile = "employees.txt";
// The collection used to hold the employee data
Employees employees;
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
employees = new Employees();
if (!employees.Load(employeesFile))
{
MessageBox.Show("Unable to load employees file");
}
else
{
PopulateListBox();
}
}
private void PopulateListBox()
{
listBoxEmployees.Items.Clear();
foreach (Employee employee in employees)
{
listBoxEmployees.Items.Add(employee.LastName + "," +
employee.FirstName);
}
listBoxEmployees.SelectedIndex = 0;
}
private void listBoxEmployees_DoubleClick(object sender, EventArgs e)
{ }
private void buttonEdit_Click(object sender, EventArgs e)
{
}
my load method:
{
public bool Load(string employeesFile)
{
bool status = false;
StreamReader inputFile = null;
string inputLine;
if (!File.Exists(employeesFile))
{
return false;
}
try
{
inputFile = new StreamReader(employeesFile);
if (inputFile != null)
{
inputLine = inputFile.ReadLine();
while (inputLine != null)
{
Employee employeeEntry =
EmployeeClass.NewEmployee(inputLine);
if (employeeEntry != null)
{
this.Add(employeeEntry);
}
inputLine = inputFile.ReadLine();
}
inputFile.Close();
}
status = true;
}
catch
{
}
return status;
}
}
the employees class code from the load method:
public class EmployeeClass
{
public static Employee NewEmployee(string employeeData)
{
if (employeeData.Length < 1)
{
return null;
}
switch (employeeData[0])
{
case 'S':
return new SalariedEmployee(employeeData);
case 'H':
return new HourlyEmployee(employeeData);
default:
return null;
the hourly employee form:
public partial class Hourly_Employee : Form {
HourlyEmployee _employeeEntry;
public Hourly_Employee()
{
InitializeComponent();
}
public HourlyEmployee employeeEntry
{
get
{
return _employeeEntry;
}
set
{
_employeeEntry = value;
}
}
private void Hourly_Employee_Load(object sender, EventArgs e)
{
textBoxlastName.Text = _employeeEntry.LastName;
textBoxfirstName.Text = _employeeEntry.FirstName;
textBoxaddress.Text = _employeeEntry.Address;
textBoxpostCode.Text = _employeeEntry.PostCode;
textBoxphoneNumber.Text = _employeeEntry.PhoneNumber;
dateTimePickerdateOfBirth.Text =
_employeeEntry.DateOfBirth.ToString();
textBoxhourlyPay.Text = _employeeEntry.HourlyPay.ToString();
textBoxoverTimePay.Text = _employeeEntry.OvertimePay.ToString();
}
}
and lastly my salaried employee form:
public partial class Salary_Employee : Form
{
SalariedEmployee _employeeEntry;
public SalariedEmployee employeeEntry
{
get
{
return _employeeEntry;
}
set
{
_employeeEntry = value;
}
}
private void Salary_Employee_Load(object sender, EventArgs e)
{
textBoxlastName.Text = _employeeEntry.LastName;
textBoxfirstName.Text = _employeeEntry.FirstName;
textBoxaddress.Text = _employeeEntry.Address;
textBoxpostCode.Text = _employeeEntry.PostCode;
textBoxphoneNumber.Text = _employeeEntry.PhoneNumber;
dateTimePickerdateOfBirth.Text =
_employeeEntry.DateOfBirth.ToString();
textBoxSalary.Text = _employeeEntry.Salary.ToString();
}
any help with this issue would be great!!
The trick is to add the employee objects to the listbox instead of only strings containing the employee names. This allows you to retrieve the selected employee directly from the listbox. Otherwise you would need a way to find the employee object belonging to a name.
Use the type of the selected item to determine the employee type and the employee form.
private void buttonEdit_Click(object sender, EventArgs e)
{
// Get the selected employee from the listBox.
object employee = listBoxEmployees.SelectedItem;
if (employee != null) { // An employee has been selected.
// Use the new C# 7.0 switch syntax in order to switch by employee type.
switch (employee) {
case SalariedEmployee sEmployee:
var sfrm = new Salary_Employee(); // Open the salaried employee form..
sfrm.employeeEntry = sEmployee;
sfrm.Show();
break;
case HourlyEmployee hEmployee:
var hfrm = new Hourly_Employee(); // Open the hourly employee form.
hfrm.employeeEntry = hEmployee;
hfrm.Show();
break;
}
}
}
In case you are using an older C# version you can test a type with
if (employee is SalariedEmployee) {
var frm = new Salary_Employee();;
frm.employeeEntry = (SalariedEmployee)employee;
frm.Show();
} else if (employee is HourlyEmployee) {
var frm = new Hourly_Employee();
frm.employeeEntry = (HourlyEmployee)employee;
frm.Show();
}
By default, an object's ToString method returns the name of the object's type. Enable the listbox to display the employees correctly by overriding the ToString method inherited from object in the common base class Employee.
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public override string ToString()
{
return LastName + ", " + FirstName;
}
}

Saving keeps overwriting itself C#

I am making an application which will save and load products. These products have three properties of a product name, customer name and firmware location. However, when I try to save them, it will only save one and keeps overwriting with the most recent product saved. The following is my code for the product class:
public class Product
{
//private product data
private string productName;
public string getProductName()
{
return this.productName;
}
public void setProductName (string inProductName)
{
this.productName = inProductName;
}
private string customerName;
public string getCustomerName()
{
return this.customerName;
}
public void setCustomerName (string inCustomerName)
{
this.customerName = inCustomerName;
}
private string firmwareLocation;
public string getFirmwareLocation()
{
return this.firmwareLocation;
}
public void setFirmwareLocation (string inFirmwareLocation)
{
this.firmwareLocation = inFirmwareLocation;
}
//constructor
public Product (string inProductName, string inCustomerName, string inFirmwareLocation)
{
productName = inProductName;
customerName = inCustomerName;
firmwareLocation = inFirmwareLocation;
}
//save method
public void Save (System.IO.TextWriter textOut)
{
textOut.WriteLine(productName);
textOut.WriteLine(customerName);
textOut.WriteLine(firmwareLocation);
}
public bool Save (string filename)
{
System.IO.TextWriter textOut = null;
try
{
textOut = new System.IO.StreamWriter(filename);
Save(textOut);
}
catch
{
return false;
}
finally
{
if (textOut != null)
{
textOut.Close();
}
}
return true;
}
At the end is my save methods.
Here is the code for when the user presses the add product button:
private void Add_Click(object sender, RoutedEventArgs e)
{
//get input from user
string inputCustomerName = customerNameTextBox.Text;
string inputProductName = productNameTextBox.Text;
string inputFirmwareLocation = firmwareTextBox.Text;
try
{
Product newProduct = new Product(inputProductName, inputCustomerName, inputFirmwareLocation);
newProduct.Save("products.txt");
MessageBox.Show("Product added");
}
catch
{
MessageBox.Show("Product could not be added");
}
}
You are not appending the text to your file, thats why it keeps overwriting the last entry over and over again.
Try to change your save method to:
public bool Save (string filename)
{
System.IO.TextWriter textOut = null;
try
{
textOut = new System.IO.StreamWriter(filename, true);
Save(textOut);
}
catch
{
return false;
}
finally
{
if (textOut != null)
{
textOut.Close();
}
}
return true;
}
Notice the "true" as the second parameter in the StreamWriter constructor. This tells the StreamWriter to append the new line.

Storing objects to a list and searching for them

I want to be able to create a series of objects in a list and then search for a particular result in that list (there may be 0, 1 or many hits) and then display the results in a text box.
This is what I have so far, but I can only seem to display the very last object I entered.
public partial class OrganiserWindow : Form
{
public OrganiserWindow()
{
InitializeComponent();
}
List<Album> AlbumList = new List<Album>();
private void createAlbum_Click(object sender, EventArgs e)
{
AlbumList.Add(new Album(albumBox.Text, artistBox.Text));
}
private void searchAlbum_Click(object sender, EventArgs e)
{
var albumResult = from album in AlbumList
where album.AlbumName != null// == albumBox.Text
select new { Name = album.AlbumName, Artist = album.ArtistName };
foreach (var item in albumResult)
{
albumResultBox.Text = String.Join(Environment.NewLine, item.Name + " " + item.Artist);
}
}
}
public class Album
{
private string albumName;
private string artistName;
public Album(string album, string artist)
{
albumName = album;
artistName = artist;
}
public string AlbumName
{
get
{
return albumName;
}
set
{
albumName = value;
}
}
public string ArtistName
{
get
{
return artistName;
}
set
{
artistName = value;
}
}
}
You forgot to use += instead of =
albumResultBox.Text += String.Join(Environment.NewLine, item.Name + " " + item.Artist);
You are accumulating state. Strings are immutable and each call to += will create a new string object for each iteration. In your case it probably won't matter but as a matter of form you should do it like this:
StringBuilder sb = new StringBuilder();
...
sb.AppendFormat("{0} {1}\r\n", item.AlbumName, item.ArtistName);
then extract a finished string from sb.ToString()
You could greatly improve the legibiity of your code by overriding ToString()
public class Album
{
public Album(string album, string artist)
{
albumName = album;
artistName = artist;
}
public string AlbumName { get; set; }
public string ArtistName { get; set; }
public override string ToString()
{
return string.Format("{0} {1}", AlbumName, ArtistName);
}
}
allowing you to write
sb.AppendLine(item);
AppendLine implicitly calls ToString then appends CRLF.
In each iteration you overwrite the text in textbox. You should append to it.
Also TextBox.Text is never null.
This line will never add album wih AlbumName == null
AlbumList.Add(new Album(albumBox.Text, artistBox.Text));
So you always return all albums when you run this query
var albumResult = from album in AlbumList
where album.AlbumName != null
select new { Name = album.AlbumName, Artist = album.ArtistName };

Categories

Resources