I have a main form with a listbox that has objects of students with a name and three scores. I want to update the selected listbox student object with new scores in a new form. I can't seem to reference or grab the selecteditem object to appear in the new form.
//Code in new form, returns null value when new form is loaded
Form1 frm = new Form1();
Student currentStudent = (Student)frm.listBox.SelectedItem;
if (currentStudent != null)
{
txtName.Text = currentStudent.Name;
}
//Code in form1
private void btnUpdate_Click(object sender, EventArgs e)
{
using(Form3 frm = new Form3())
{
DialogResult button = frm.ShowDialog();
}
}
CodePudding user response:
I reproduce your problem.
The listbox control is bound to the data source.
private void button1_Click(object sender, EventArgs e)
{
this.listBox1.Items.Clear();
// create data
List<Student> students = new List<Student>();
students.Add(new Student() { Name = "admin", Engrade = 78, Magrade = 88, Clugrade = 89});
students.Add(new Student() { Name = "tony", Engrade = 75, Magrade = 77, Clugrade = 84 });
students.Add(new Student() { Name = "lucy", Engrade = 85, Magrade = 67, Clugrade = 69});
// bind data without modifying the binding
this.listBox1.DataSource = students;
this.listBox1.DisplayMember = "Name"; // Properties of display content data
this.listBox1.ValueMember = "Engrade";// item value attribute of data
}
Get the value of the current selection.
private void button2_Click(object sender, EventArgs e)
{
// selection item collection of items
var items = this.listBox1.SelectedItems;
string strItem = "";
foreach(var item in items)
{
Student stu1 = (Student)item;
if (stu1 != null)
{
strItem = stu1.Name.ToString() ",";
}
// strItem = stu1.Name.ToString() ",";
}
textBox1.Text = strItem;
StuName.Name = strItem;
}
Open new form
private void button3_Click(object sender, EventArgs e)
{
using (Form2 frm = new Form2())
{
DialogResult button = frm.ShowDialog();
}
}
private void Form2_Load(object sender, EventArgs e)
{
textBox1.Text = StuName.Name.ToString();
}
Test items
CodePudding user response:
I recommend using an event to push changes from the child form to the main form.
Student class
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public decimal Score { get; set; }
public override string ToString() => $"{FirstName} {LastName}";
}
Mock-up some data
public class Operations
{
public static List<Student> Students()
{
return new List<Student>()
{
new Student() {Id = 1, FirstName = "Jim", LastName = "Adams", Score = 87m},
new Student() {Id = 2, FirstName = "Mary", LastName = "Jones", Score = 73m},
};
}
}
Main form, note we subscribe to a custom event in the child form. A BindingSource connects to the ListBox where the BindingSource data source comes from a BindingList of Student.
using System.ComponentModel;
namespace StackoverflowApp
{
public partial class Form1 : Form
{
private readonly BindingSource _bindingSource = new BindingSource();
private BindingList<Student> _bindingList = new BindingList<Student>();
public Form1()
{
InitializeComponent();
Shown = OnShown;
}
private void OnShown(object sender, EventArgs e)
{
_bindingList = new BindingList<Student>(Operations.Students());
_bindingSource.DataSource = _bindingList;
listBox1.DataSource = _bindingSource;
}
private void ShowFormButton_Click(object sender, EventArgs e)
{
using ChildForm form = new ChildForm(_bindingList[_bindingSource.Position]);
form.OnStudentChanged = FrmOnOnStudentChanged;
form.ShowDialog();
form.OnStudentChanged -= FrmOnOnStudentChanged;
}
private void FrmOnOnStudentChanged(Student student)
{
_bindingList[_bindingSource.Position] = student;
_bindingList.ResetItem(_bindingSource.Position);
}
private void CurrentButton_Click(object sender, EventArgs e)
{
var student = _bindingList[_bindingSource.Position];
MessageBox.Show($"{student.Id}, {student.FirstName}, {student.LastName}, {student.Score}");
}
}
}
Child form gets the student from the constructor, assigns to a private var which in turn is data bound to controls on the form.
namespace StackoverflowApp
{
public partial class ChildForm : Form
{
public delegate void StudentUpdate(Student student);
public event StudentUpdate OnStudentChanged;
private readonly Student _student;
public ChildForm()
{
InitializeComponent();
}
public ChildForm(Student student)
{
InitializeComponent();
_student = student;
FirstNameTextBox.DataBindings.Add(
"Text", student, nameof(Student.FirstName));
LastNameTextBox.DataBindings.Add(
"Text", student, nameof(Student.LastName));
ScoreNumericUpDown.DataBindings.Add(
"Value", student, nameof(Student.Score));
}
private void UpdateButton_Click(object sender, EventArgs e)
{
// TODO - Validation
OnStudentChanged?.Invoke(_student);
}
}
}
You should consider adding validation in the child form prior to sending data back to the main form. Also might check to see if there is a current item selected prior to sending data to the child form.
Note that in the code presented the ListBox is only referenced once, one should only touch controls when absolutely necessary, instead work with components e.g. BindingSource, BindingList instead.