C# association with xaml - c#

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;
}

Related

C# DataGrid not showing Data in WinForm

I have a DataGridView that I am trying to populate as follows:
List<pupil> listOfUsers = new List<pupil>(); // Create a new list
listOfUsers = pupil.LoadPupilDetails(); // Populate the list with a list of all users
dgvPupil.DataSource = listOfUsers;
The code works in another project of mine and I followed the same process but it won't appear. The list does return users from a text file. I have also break pointed and can confirm the dgvPupil.DataSource shows this data but it simply won't show on the rendered form.
Initailly, I had this code in the form load event, but I then tried applying it through a manual button click event to no avail.
I would really appreciate some help with this.
Sorry for the delay and thank you so much for trying to help.
I usually use encapsulation but for this program, I was aiming for simplicity and was using public properties. So I learned that my class required the properties to have getters and setters so that backing fields would be created at run time. This allowed the data to protrude through to the DGV!
See if the simple code sample helps using mocked data. What is needed is to see code that you have as your current code does not really provide enough details.
Note 1 I created the columns for the DataGridView in the designer, set header text and DataPropertyName to match up with each property in the Pupil class.
Note 2 Learn to use a BindingSource.
I would recommend creating a new form devoid of anything other than what is needed to diagnose the current issue.
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace PupilsProject
{
public partial class Form1 : Form
{
private readonly BindingSource _bindingSource = new BindingSource();
public Form1()
{
InitializeComponent();
dgvPupil.AutoGenerateColumns = false;
_bindingSource.DataSource = Mocked.Pupils();
dgvPupil.DataSource = _bindingSource;
foreach (DataGridViewColumn column in dgvPupil.Columns)
{
Console.WriteLine(
$"{column.Name}, {column.DataPropertyName}, {column.DefaultCellStyle.Format}");
}
}
}
class Pupil
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
}
class Mocked
{
public static List<Pupil> Pupils() =>
new List<Pupil>
{
new Pupil()
{
FirstName = "Jim",
LastName = "Adams",
BirthDate = new DateTime(1990, 1, 2)
},
new Pupil()
{
FirstName = "Mary",
LastName = "Jones",
BirthDate = new DateTime(1980, 11, 4)
},
new Pupil()
{
FirstName = "Mile",
LastName = "White",
BirthDate = new DateTime(1970,10,9)
}
};
}
}
Output for each DataGridView column
FirstNameColumn, FirstName,
LastNameColumn, LastName,
BirthDateColumn, BirthDate, d

How to Output from Generic Array List, to Listbox?

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!

ObservableCollection didn't Bind the data in listbox

I need to show the WCF service Return Value(LIST) in Silverlight Listbox.
create GetAllAgents Class like,
public class GetAllAgents
{
public List<string> FirstName { get; set; }
public GetAllAgents(List<string> firstName)
{
FirstName = firstName;
}
}
The Following Method used for Consume the WCF Service
public partial class AgentQueue : UserControl
{
ChatACDService.ChatACDServiceClient ChatAcdClient = new ChatACDService.ChatACDServiceClient();
public ObservableCollection<GetAllAgents> _GetAllAgents = new ObservableCollection<GetAllAgents>();
public AgentQueue()
{
InitializeComponent();
LoadAgentList();
this.AllList.DataContext = _GetAllAgents;
}
private void LoadAgentList()
{
ChatAcdClient.GetAllAgentListCompleted += new EventHandler<GetAllAgentListCompletedEventArgs>(ChatAcdClient_GetAllAgentListCompleted);
ChatAcdClient.GetAllAgentListAsync();
}
void ChatAcdClient_GetAllAgentListCompleted(object sender, GetAllAgentListCompletedEventArgs e)
{
if (e.Error != null)
{
}
else
{
// AllAgents.ItemsSource = e.Result;
_GetAllAgents.Add(new GetAllAgents(e.Result.ToList()));
}
}
I use the following code For create List Box in XAML page
<ListBox x:Name="AllList" ItemsSource="{Binding}"
DisplayMemberPath="FirstName"
Margin="403,54,0,35" HorizontalAlignment="Left" Width="101" />
But The Output like ,
I need to show the WCF method's result(return type is list) in Listbox by using ObservableCollection.What are the changes are need to make in above Program?
Actually it works pretty well:
You ask to display the Member Path "FirstName" of your object GetAllAgents.
But the Member Path "FirstName" is a list of string.
So your XAML display what you expect from it: the toString() conversion of your memberPath.
And the default toString of your member path which is FirstName which is a list of string is: System.Collection.Generic.List[System.String]
I guess what you expect is that your list of first name should be the item source of your ListBox.
So if your only need is to display their firstName, just replace
public ObservableCollection<GetAllAgents> _GetAllAgents = new ObservableCollection<GetAllAgents>();
By
public ObservableCollection<string> _GetAllAgents = new ObservableCollection<string>();
and
_GetAllAgents.Add(new GetAllAgents(e.Result.ToList()));
By
foreach (var agentName in e.Result.ToList())
{
_GetAllAgents.Add(agentName);
}
And it will display the name of your agent.
If you need mor than that, you will need to create a viewModel per agent object and a dataTemplate to let know Silverlight how you want it to be display.
Hope it helps.

Behind the scenes property of Winforms listbox item

So I'm going back and cleaning up code I did years ago. In one part, (and I used this several times) I have a list box displaying employee names such as
Smith, John
Doe, Jane
When the user clicks the name, I do something like
String unBrokenName = ListBox1.SelectedItem.ToString();
String LastName = unBrokenName.Substring(...
You get the idea, I extract the first and last name based upon the ", "
Then I do this to get the employee from the sql database.
Employee SelectedEmployee = Employee.GetEmployeeByFirstLast(FirstName, LastName);
At the time, it was the best I knew. Now it feels wrong, because I KNOW I should be able to get the sql ID of the employee when they select it, like
int EmployeeId = SOMELISTBOXSELECTEDITEMPROPERTY;
Employee SelectedEmployee = Employee.GetEmployeeByID(EmployeeId);
Is there some property for a listbox item that will store this id while displaying the same name the users are used to seeing?
You can actually add anything you'd like to a listbox:
class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return this.Name;
}
}
And then:
listBox1.Items.Add( new Foo() { Id = 101, Name = "Foo Bar" } );
listBox1.Items.Add( new Foo() { Id = 102, Name = "Foo Bar Jr." } );
The SelectedItem property will now give you the selected Foo, while displaying the Name property in the list itself.
private void listBox1_SelectedIndexChanged( object sender, EventArgs e )
{
Foo item = ( listBox1.SelectedItem as Foo );
if( item != null )
{
// use item.Id here
}
}
Instead of overriding ToString, you can also use the DisplayMember property of the listbox to select which property the listbox will display.
You can do something like this:
listBox1.DataSource = employeesList;
listBox1.DisplayMember = "LastName";
listBox1.ValueMember = "EmployeeId";
When you run your application the listbox will have the list of employees that you are passing and it will show the LastName. But when you select an item, you can access the id by:
`listBox1.SelectedValue();`
And then in the listbox1_Click event something like:
if (listBox1.SelectedIndex != -1)
{
int employeeId = listBox1.SelectedValue();
//do something here;
}

Formatting and displaying data from an access database (WPF, C#)

Evening all,
To the point: Within my WPF application I would like to display data from an access database within a listbox in the format of a ToString method created within another class. -- I can display the data, but it does not contain formatting.
Context of my question:
I am creating an application for my graded unit at college which adds, deletes and displays data from an access database. I am having no trouble with adding or deleting data to the database, however, I am struggling to display the data in a particular format.
Due to specific requirements, I have had to create an abstract Games class, with the subclasses Platform and Mobile (games).
I would like to know how to display data from an access database in a listbox (though this is flexible to change), whilst formatting the content to a previously created ToString() method in both the Platform and Mobile class. I understand that I may have to create two separate methods to display platform and mobile games, as they each have an additional variable.
Currently, I am storing my listPlatform() method within my Catalogue class, which is accessed from a separate window (EmployeeWindow, which contains the list view box, then accessing this method and calling it via a button_click event.
Catalogue class --
public List<string> listPlatform()
{
List<string> data = new List<string>();
string queryString = "SELECT ID, Game_Name, Developer, Publisher, Genre, Age_Rating, Price, Quantity, Description, Platform FROM GameDetails";
using (OleDbConnection connection = new OleDbConnection(ConnString))
{
OleDbCommand command = new OleDbCommand(queryString, connection);
connection.Open();
OleDbDataReader reader = command.ExecuteReader();
while (reader.Read())
{
int id = reader.GetInt32(0);
string gName = reader.GetString(1);
string gDeveloper = reader.GetString(2);
string gPublisher = reader.GetString(3);
string gGenre = reader.GetString(4);
int gAgeRating = reader.GetInt32(5);
var gPrice = reader.GetValue(6);
var gQuantity = reader.GetValue(7);
var gDescription = reader.GetValue(8);
var gPlatform = reader.GetValue(9);
data.Add(id + gName + gDeveloper + gPublisher + gGenre + gAgeRating + gPrice
+ gQuantity + gDescription + gPlatform);
}
reader.Close();
}
return data;
}
EmployeeWindow --
private void btnDisplay_Click(object sender, RoutedEventArgs e)
{
List<string> data = theCatalogue.listPlatform();
lstvwGames.Items.Clear();
foreach (string s in data)
{
lstvwGames.Items.Add(s);
}
}
Platform class --
/// <summary>
/// Returns a string representation of a Platform game
/// </summary>
/// <returns></returns>
public override string ToString()
{
string strout = string.Format(base.ToString() + "Platform:{0}", platform);
return strout;
}
I hope that my question makes sense and that I have provided enough information to give you some understanding of what it is that I am trying to do.
I think that, in this scenario, you need to add another class to your code.
The Game class that you could model looking at the fields present in your database table
public class Game
{
public int ID {get;set;}
public string GameName {get;set;}
public string Developer {get;set;}
public string Publisher {get;set;}
public string Genre {get;set;}
public string Age_Rating {get;set;}
public decimal Price {get;set;}
public int Quantity {get;set;}
public string Description {get;set;}
public string Platform {get;set;}
public override string ToString()
{
return this.GameName + " - " + this.Genre;
}
}
Now in the Catalogue class, when you read your database you build a List<Game> not a List<String>
public List<Game> listPlatform()
{
.....
List<Game> games = new List<Game>();
while (reader.Read())
{
Game g = new Game();
g.ID = reader.GetInt32(0);
g.GameName = reader.GetString(1);
... and so on for the rest of fields
games.Add(g);
}
...
return games;
}
Finally, when you need to add the games to your ListBox, you could write
private void btnDisplay_Click(object sender, RoutedEventArgs e)
{
List<Game> data = theCatalogue.listPlatform();
lstvwGames.Items.Clear();
foreach (Game g in data)
{
lstvwGames.Items.Add(g.ToString());
}
}
And you have a list filled with GameName and Genre.
EDIT to complete this answer,
Finally, you could directly set the DataSource, DisplayMember and ValueMember properties of the ListBox with your List<Game> and some of its properties removing the need to have a loop to fill items
private void btnDisplay_Click(object sender, RoutedEventArgs e)
{
lstvwGames.ValueMember = "ID";
lstvwGames.DisplayMember = "GameData";
lstvwGames.DataSource = theCatalogue.listPlatform();
}
In this example the DisplayMember property is assigned to a new GameData field that you should define inside your Game class. This new readonly property could be the actual return value of the ToString method of the same class or another value of your choice
public class Game
{
.....
public string GameData
{
// Only a getter, thus readonly
get
{
return this.ToString();
}
}
}
Of course you could change the ToString method or the GameData property inside the Game class to return the info you really want to display in the listbox.
I do not see you using the tostring override method. Maybe you meant to use it here?
lstvwGames.Items.Add(s.ToString());

Categories