How to Output from Generic Array List, to Listbox? - c#

I am trying to output from Array list to a Listbox. My problem is I think is I do not know how to connect the Class to the Generic array list a made? The end result should look like this:
And the information should be then sorted like so: all the information enters the first list box, and then the above 18 goes to adults, and the below 18 to kids. My class looks like this:
namespace Patients
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public String Password { get; set; }
public Person() //Constructor
{
Age = 0;
Password = "";
}
public Person (string name, int age, string password) //Parameters
{
this.Name = name;
this.Age = age;
this.Password = password;
}
public override string ToString() //
{
return Name + Age.ToString() + Password; //outputs as a string
// return Name + " (" + Age + " years) " + Password ;
}
}
}
namespace Patients
{
public partial class WebForm1 : System.Web.UI.Page
{
public static void Page_Load(object sender, EventArgs e)
{
}
public void ButtonAdd_Click(object sender, EventArgs e)
{
Person p = new Person();
List<string> People = new List<string>();
People.Add(TextBoxName.Text);
People.Add(TextBoxAge.Text);
People.Add(TextBoxPassword.Text);
foreach (object Person in People)
{
ListBoxAll.Items.Add(p.Name + p.Age.ToString() + p.Password);
}
if (p.Age > 18)
{
ListBoxAdults.Items.Add(p.Name + p.Age.ToString() + p.Password);
}
else
{
ListBoxKids.Items.Add(p.Name + p.Age.ToString() + p.Password);
}
}
}
}

I think your problem is, that you don't set the Properties. In Fact you don't need a List at all, but you can use a List to keep hold of your patients. It's still not necessary though:
namespace Patients
{
public partial class WebForm1 : System.Web.UI.Page
{
// Define Property and initialize List
public List<Person> patients{ get; } = new List<Person>();
public static void Page_Load(object sender, EventArgs e)
{
}
public void ButtonAdd_Click(object sender, EventArgs e)
{
// Use the Constructor with Parameters
Person p = new Person(TextBoxName.Text, TextBoxAge.Text, TextBoxPassword.Text);
// Add your patient to your List
patients.Add(p);
// Use the ToString() of your Person
ListBoxAll.Items.Add(p.ToString());
if (p.Age > 18)
{
ListBoxAdults.Items.Add(p.ToString());
}
else
{
ListBoxKids.Items.Add(p.ToString());
}
}
}
}

Looks like you are mixing and matching a bit.
Try something like this.
Person p = new Person();
p.Name = TextBoxName.Text;
p.Age= TextBoxAge.Text;
p.Password= TextBoxPassword.Text;
ListBoxAll.Items.Add(p);

A few tricks that are nice to us, first off you can declare defaults for properties like so:
public string Name { get; set; } = "Steve";
public int Age { get; set; } = 1;
public String Password { get; set; } = "password";
However, it should also be noted that "" is the default for strings already and 0 is the default for non-nullable int, so you don't even need to worrying about those default values.
Declaring Age = 0; in the constructor is basically a waste of time in this case. (If it was a nullable int however the default is null)
Next up, since you are okay with defaults, you don't need to declare properties in the constructor like you are.
You can completely remove the constructor and just do the following:
var myPerson = new Person { Name = "Steve", Age = 18, Password = "Foo" };
Next up, you are losing all your existing people as soon as you exit the scope of the button click.
Instead you'll want to declare two lists of people outside the scope of the click method (that way they persist), something like "Adults" and "Children"
Then perhaps make a method called "PopulateLists" that would do the following:
Clear all list boxes
Add to each box the list of each groups names that apply (you can make an IQueryable by using Linq and Select statements on your list)
When you click the button, you should make a new person, assign it to the right list, then call PopulateLists()
Here's the info you need to get started:
Linq selection to get list of properties (in this case Im going to turn a List of People into a List of Ages, you can do the same with names though)
var ages = People.Select(p => p.Age);
The .Items property of a ListBox works the same as a list, it just visually shows itself. It's a list of strings specifically.
So for example you can do things like...
MyListBox.Items.Clear();
MyListBox.Items.Add(...);
MyListBox.Items.AddRange(...);
etc etc.
That should get you started!

Related

Get values out of collections with FastMember

I use FastMember to get values out of objects and nested objects. If a property is a string or int everything works fine. But now I want to get the values also for collections. Here is my code so far:
// Set accessor
var sourceAccessor = ObjectAccessor.Create(source);
if (sourceAccessor.Target.GetType().GetInterface(nameof(ICollection)) != null || sourceAccessor.Target.GetType().GetInterface(nameof(IEnumerable)) != null)
{
foreach (/* idk */)
{
// READ & RETURN VALUES HERE
}
}
An object could look like this:
{
Id: 1,
Surname: Doe,
Prename: John,
Professions: [
{ Name: ab },
{ Name: xy }
]
}
Which means professions would result in a problem.
Any advise how I can solve this problem? Thanks!
It's not obvious from the question what the data type of the source variable is, but you should just be able to check if the value returned by the accessor implements IEnumerable or not and act accordingly.
Here's a quick worked example that iterates over the Professions property of a 'Person' object and just dumps the ToString() representation to the console - if you wanted to dive into each Profession object using FastMember you could construct another ObjectAccessor to do it, I guess - it's not clear what your goal is once you're iterating.
The same tactic will work if you're building the ObjectAccessor directly from an array - you just check if the accessor.Target is IEnumerable and cast-and-iterate in a similar fashion.
class Program
{
static void Main(string[] args)
{
var p = new Person
{
Professions = new List<Profession>
{
new Profession("Joker"),
new Profession("Smoker"),
new Profession("Midnight toker")
}
};
var accessor = ObjectAccessor.Create(p);
var professions = accessor[nameof(Person.Professions)];
if (professions is IEnumerable)
{
foreach (var profession in (IEnumerable)professions)
{
Console.WriteLine(profession);
}
}
}
}
class Person
{
public List<Profession> Professions { get; set; }
}
class Profession
{
public string Name { get; set; }
public Profession( string name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
}

C# Lists - do I use Class Methods (Get/ Set etc) again once the data is in a list?

A quick question on OOP. I am using a list together with a class and class constructor. So I use the class constructor to define the data set and then add each record to my list as the user creates them.
My questions is once the data is in the list and say I want to alter something is it good practice to find the record, create an instance using that record and then use my class methods to do whatever needs doing - and then put it back in the list?
For example below I have my class with constructor. Lets say I only want the system to release strCode if the Privacy field is set to public. Now just using Instances I would use for example Console.WriteLine(whateverproduct.ProductCode) but if the record is already in a list do i take it out of the list - create an instance and then use this method?
class Product
{
private String strCode;
private Double dblCost;
private Double dblNet;
private String strPrivacy;
public Product(String _strCode, Double _dblCost, Double _dblNet, String _strPrivacy)
{
strCode = _strCode;
dblCost = _dblCost;
dblNet = _dblNet;
strPrivacy = _strPrivacy;
}
public string ProductCode
{
get
{
if (strPrivacy == "Public")
{
return strCode;
}
else
{
return "Product Private Can't release code";
}
}
}
Lets say we have the following:
public class Test
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Amount { get; set; }
private string _test = "Some constant value at this point";
public string GetTest()
{
return _test;
}
public void SetTest()
{
//Nothing happens, you aren't allow to alter it.
//_test = "some constant 2";
}
}
public class Program
{
public static void Main(string[] args)
{
List<Test> listOfTest = new List<Test>()
{
new Test() {Id = 0, Name = "NumberOne", Amount = 1.0M},
new Test() {Id = 1, Name = "NumberTwo", Amount = 2.0M}
};
Test target = listOfTest.First(x => x.Id == 0);
Console.WriteLine(target.Name);
target.Name = "NumberOneUpdated";
Console.WriteLine(listOfTest.First(x => x.Id == 0).Name);
Console.WriteLine(listOfTest.First(x => x.Id == 0).GetTest());//This will alsways be "Some constant value at this point";
Console.ReadLine();
}
}
Technically you could do away with the SetTest method entirely. However, I included it to demonstrate, what it would look like, if you wanted to alter _test.
You don't want to ever create a new instance of a class, you already have an instance of. you can just alter the class where it is allowed by the author of the class, where you need to. And keep that class reference for as long as you need it. Once you are done, the reference will be garbage collected, once the program finds no active reference to your object(instance).

C# association with xaml

I am trying to make an enroll/withdraw student into course project however I am not entirely sure how to add specific students to specific course.
I have a Course and Student class, and then a xaml window with a combobox, and list box with appropriate buttons.
When I press the enrol right now it simply takes the selected student and adds it into the "EnrolledStudents" text box to display the name however it doesn't actually assign it to the selected Course.
Code I have so far:
public MainWindow()
{
InitializeComponent();
Course bsc = new Course("BSc(Hons) Applied Computing");
Course hnd = new Course("Higher National Diploma (HND) Applied Computing");
Course partTime = new Course("Computer Science Part Time (MSc)");
Student andy = new Student("Andy", "Watt");
Student dave = new Student("Dave","Newbold");
Student daniel = new Student("Daniel","Brown");
lbCourses.Items.Add(bsc);
lbCourses.Items.Add(hnd);
lbCourses.Items.Add(partTime);
cbStudents.Items.Add(andy);
cbStudents.Items.Add(dave);
cbStudents.Items.Add(daniel);
}
and the enroll button click code:
private void butEnroleStudent_Click(object sender, RoutedEventArgs e)
{
cbStudents.SelectedItem.ToString();
lbEnroledStudents.Items.Add(cbStudents.SelectedItem);
}
but I am not sure where to go from here. My main issue is I don't know how to select the Student and Course instead of the string values.
As BradleyDotNET suggests, MVVM would be a lot easier for you to use, especially if your UI is going to get a lot more complicated. Also, any application like this is most likely going to rely on a database behind the scenes and hence you would be looking to bind all of your data controls.
That said, here is a sample that would achieve what you are trying to do there.
Presuming your Student class looks something like this:
private class Student
{
public String FirstName { get; set; }
public String Surname { get; set; }
public Student(String firstName, String surname)
{
FirstName = firstName;
Surname = surname;
}
public override string ToString()
{
return FirstName + " " + Surname;
}
}
And your Course class something like this:
private class Course
{
public String Name { get; set; }
public List<Student> EnrolledStudents { get; set; }
public Course(String name)
{
Name = name;
EnrolledStudents = new List<Student>();
}
public override string ToString()
{
return Name;
}
}
(Note that I have added a List to store the students enrolled on the given course)
Rather than adding to the Items property of your ListBox and ComboBox create collections that we can bind to:
private List<Student> _students;
private List<Course> _courses;
Constructing your test data then looks like this:
_courses = new List<Course>();
_courses.Add(new Course("BSc(Hons) Applied Computing"));
_courses.Add(new Course("Higher National Diploma (HND) Applied Computing"));
_courses.Add(new Course("Computer Science Part Time (MSc)"));
_students = new List<Student>();
_students.Add(new Student("Andy", "Watt"));
_students.Add(new Student("Dave", "Newbold"));
_students.Add(new Student("Daniel", "Brown"));
lbCourses.ItemsSource = _courses;
cbStudents.ItemsSource = _students;
Then when you click your enroll button
private void butEnroleStudent_Click(object sender, RoutedEventArgs e)
{
if (lbCourses.SelectedIndex >= 0 && cbStudents.SelectedIndex >= 0)
{
// Both a student and course are selected
Course selectedCourse = (Course)lbCourses.SelectedItem;
Student studentToAdd = (Student)cbStudents.SelectedItem;
if (!selectedCourse.EnrolledStudents.Contains(studentToAdd))
{
// Course does not already contain student, add them
selectedCourse.EnrolledStudents.Add(studentToAdd);
lbEnroledStudents.Items.Refresh();
}
}
}
Finally, to show the enrolled students in lbEnroledStudents as you click through the courses, you will need to hook up a new event handler in the xaml:
<ListBox x:Name="lbCourses" SelectionChanged="lbCourses_SelectionChanged"></ListBox>
And in the code behind:
private void lbCourses_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Course selectedCourse = (Course)lbCourses.SelectedItem;
lbEnroledStudents.ItemsSource = selectedCourse.EnrolledStudents;
}

How can I share variables between Web forms?

I am developing a web application on C# .Net and I need to pass variables from form to another form. For example, in the first form I have person class as following;
public class Person
{
private string _Name;
private string _Surname;
private string _DateOfBirth;
private string _Gender;
private string _Symptoms;
public Person()
{
Name = "Not available";
Surname = "Not available";
DateOfBirth = "Not available";
Gender = "Not available";
Symptoms = "Not available";
}
public string Name
{
get { return _Name; }
set { _Name = value; }
}
public string Surname
{
get { return _Surname; }
set { _Surname = value; }
}
public string DateOfBirth
{
get { return _DateOfBirth; }
set { _DateOfBirth = value; }
}
public string Gender
{
get { return _Gender; }
set { _Gender = value; }
}
public string Symptoms
{
get { return _Symptoms; }
set { _Symptoms = value; }
}
}
Then I assign values;
protected void Page_Load(object sender, EventArgs e)
{
Person MyPerson = new Person();
MyPerson.Name = txtName.Text;
MyPerson.Surname = txtSurname.Text;
MyPerson.DateOfBirth = txtBirth.Text;
MyPerson.Gender = listGender.Text;
MyPerson.Symptoms = checked(listSymptoms.Text);
}
So, how can I use these values into another form?
consider Another_form is a new form's class that contain a method should accept an object(person class)... for example
public void foo(Person obj)
{ ///your code }
that's it... then you have to pass variable from another form like
protected void Page_Load(object sender, EventArgs e)
{
Person MyPerson = new Person();
MyPerson.Name = txtName.Text;
MyPerson.Surname = txtSurname.Text;
MyPerson.DateOfBirth = txtBirth.Text;
MyPerson.Gender = listGender.Text;
MyPerson.Symptoms = checked(listSymptoms.Text);
another_form f=new another_form();
f.foo(MyPersion)
}
You could make your form produce a Person instance instead:
// within your form class, whatever it is
public Person CreatePerson()
{
Person MyPerson = new Person();
MyPerson.Name = txtName.Text;
MyPerson.Surname = txtSurname.Text;
MyPerson.DateOfBirth = txtBirth.Text;
MyPerson.Gender = listGender.Text;
MyPerson.Symptoms = checked(listSymptoms.Text);
return MyPerson;
}
Then, from anywhere in your code, call your form instance's CreatePerson method:
var personFromUI = yourFormInstance.CreatePerson();
That is one way to do it.
You could also expose the person as a property of your form, or pass a Person instance throughout your application objects, be it forms, controls, controllers, etc... while this goes beyond the scope of your question, this would be the preferred way because it keeps your UI code and your business code separated.
I'd advise that you look into separation of concerns. You may learn a trick or two there about proper application design.
Are you saying that you have populated a person object and then on another form you'd like to reference the same instance of that person object? Probably the simplest way would be to store the object in Session and then retrieve it on the second form.
protected void Page_Load(object sender, EventArgs e)
{
Person MyPerson = new Person();
MyPerson.Name = txtName.Text;
MyPerson.Surname = txtSurname.Text;
MyPerson.DateOfBirth = txtBirth.Text;
MyPerson.Gender = listGender.Text;
MyPerson.Symptoms = checked(listSymptoms.Text);
Session["CurrentPerson"] = MyPerson;
}
Personally, I don't normally use session this way and instead build that type of workflow into my apps persistence layer (e.g. Sql Server, Redis).

Implementing a find system for a ListView in C#

I am creating an application in C# using a ListView control that lets you create lists. I am implementing a Find function using the Find() method. Here’s my code:
if (findTextBox.Text != "")
{
ListViewItem[] lviFoundList = listItemsList.Items.Find(findTextBox.Text, true);
amountFound.Text = "Found " + Convert.ToString(lviFoundList.Count());
if (lviFoundList.Count() != 0)
{
int firstItemIndex = lviFoundList[0].Index;
listItemsList.Items[firstItemIndex].Selected = true;
}
}
else
{
amountFound.Text = "Found 0";
}
However, it doesn’t return any matches. What am I doing wrong?
Find method requires your listView item's Name, did you set your list view item's name property? If you want to search for text you can use this:
var lviFoundList = new List<ListViewItem>();
foreach(var item in listItemsList.Items)
{
if(item.Text == findTextBox.Text) lviFoundList.Add(item);
}
The Find() Method looks at the ListViewItem's name, not it's text.
You want this instead:
if (findTextBox.Text != "")
{
List<ListViewItem> items = new List<ListViewItems>();
foreach ListViewItem lvi in listItemsList.Items
{
if (lvi.Text == findTextBox.Text)
items.Add(lvi);
}
amountFound.Text = "Found " + Convert.ToString(lviFoundList.Count());
if(lviFoundList.Count() != 0)
{
int firstItemIndex = lviFoundList[0].Index;
listItemsList.Items[firstItemIndex].Selected = true;
}
}
else
{
amountFound.Text = "Found 0";
}
Honestly, the ListView.Find() method is rather poor and it's much easier to roll your own with LINQ. Think about what Find really is trying to accomplish -- a specific filtering, typically one record.
The first step, if you haven't already, would be to keep a cached collection of your data objects. Let's assume you have a list of Person classes like so:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string JobTitle { get; set; }
public DateTime DateOfBirth { get; set; }
}
Then in your MainForm you have a ListView and a member variable people defined as a List<Person>. Your ListView.Items should reflect the contents of this List<Person>.
So now maybe you want to find a person based on their FirstName or LastName, right? You could use LINQ in a function like so:
int FindFirstIndexOfPersonNamed(string firstOrLastName)
{
// WARNING: This is case sensitive!
return people.FindIndex(p => p.FirstName.Contains(firstOrLastName) || p.LastName.Contains(firstOrLastName));
}
Since your ListView.Items should be reflecting your List<Person> the index should be identical:
// Get the found item and do whatever you want with it...
var selectedListViewItem = listView.Items[index];

Categories