-1

I am new to C# and have started a program that I want to take in data from user, send to list box, sort list box and then save results. This happens via two text boxes:

txtUsername txtResult

below the text box is a button that is disabled unless both text fields are entered, the button (btnAdd) adds the results and name of student to two separate list boxes:

lstUsername lstResult

by disabling the button I ensure only both name and result are entered and sent to the list boxes in unison, the next bit is where it becomes tricky for me..

I want to be able to be able to sort the list boxes in ascending order to see at a glance the user with the highest result, but this wont be achieved due to the entries in each list box not being linked to one another. for example if a put a line of code to sort the high scores they then would not match the user in the list box parallel. I have only touched on arrays but understand the data between Username and result in a list box would need to be linked in some way so they are matched even after sorting.

This is the current code on the button that sends both the username and result to the list boxes:

        InitializeComponent();
        {
            btnAdd.Enabled = !string.IsNullOrWhiteSpace(txtResult.Text);
            btnAdd.Enabled = !string.IsNullOrWhiteSpace(txtUsername.Text);
        }


         private void btnAdd_Click(object sender, EventArgs e)
        {
            lstUsername.Items.Add(txtUsername.Text);
            lstResult.Items.Add(txtResult.Text);
            //There is also a counter that counts entries once being sent to the list
            txtScoreCount.Text = lstUsername.Items.Count.ToString(); 
            lstResult.Items.Count.ToString();
            txtResult.Clear();
            txtUsername.Clear();
            txtUsername.Focus();
            txtUsername.SelectAll();

        }

If anyone can provide advice on how I am able to match the entries of two separate list boxes together I would be very grateful, I am also happy to provide more code if required. Any advice is beneficial to me. I will be able to work out saving the data and loading it back into the lists myself once I have the data in two lists bound, thank you.

Melby
  • 23
  • 4
  • Your InitiailzeComponent code looks like you think that code will run whenever that condition is met. It only runs once. Use the TextChanged events of the TextBoxes. It also looks like you expect it to work as an "AND". It won't. The txtUserName.Text will determine the button's enabledness, not the txtResult.Text. – LarsTech Jan 13 '20 at 18:56
  • [Binding a TextBox to a ListBox SelectedItem](https://stackoverflow.com/a/57235083/7444103) – Jimi Jan 13 '20 at 18:56
  • @LarsTech I should have stated that that entry is only in the initialise component so it is disabled upon form load. I also have the code applied to each TextChanged events for Username and Result. but thank you! – Melby Jan 13 '20 at 19:09
  • But you already know the TextBoxes are empty at startup, so just leave it disabled in the designer. – LarsTech Jan 13 '20 at 19:11
  • Do not assign strings to ListBox items; that is going to wreck data binding. Instead [bind to a collection](https://stackoverflow.com/questions/17547565/). – Dour High Arch Jan 13 '20 at 19:14
  • @LarsTech I see now, many thanks I have now added code to disable button in designer. – Melby Jan 13 '20 at 19:32
  • Thank you for the responses, I am struggling with the binding sources but that does seem the way to go. I have a datagrid and bindingsource, the data grid contains two columns Username and Result. but I am unable to find a code example that would move text box entries into those columns – Melby Jan 13 '20 at 20:36
  • When you have Controls bound to DataSource, add new data to the DataSource, not to the controls (DataGridView, ListBox, ComboBox will automatically updated. Use a BindingSource to *connect* all your controls to a DataSource, as shown in the sample code I linked). – Jimi Jan 13 '20 at 20:38
  • `DataGridView` control is the **right tool for the job** here! – Fabio Jan 13 '20 at 23:26

1 Answers1

0

This should get you somewhere.

using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;

namespace Students2
{
    public partial class Form1 : Form
    {
        public class Student : ListViewItem
        { 
            public Student(string name, float grade) : base()
            {
                this.Text = name;
                //Add its grade as a subitem automatically.
                this.SubItems.Add(new ListViewSubItem(this, grade.ToString()));
            }
        }

        public class ListViewItemComparer : IComparer
        {
            private int ColIdx = 0;
            public ListViewItemComparer(int index) { ColIdx = index; }
            public int Compare(object x, object y) 
            { 
                switch(ColIdx)
                {              
                    case 1: //Numeric
                        {
                            var a1 = Convert.ToSingle(((ListViewItem)x).SubItems[ColIdx].Text);
                            var a2 = Convert.ToSingle(((ListViewItem)y).SubItems[ColIdx].Text);
                            return a1.CompareTo(a2);
                        }
                    default:
                        return String.Compare(((ListViewItem)x).SubItems[ColIdx].Text, ((ListViewItem)y).SubItems[ColIdx].Text);
                }              
            }
        }

        public Form1()
        {
            InitializeComponent();

            //Initialize ctrls
            TextBox txtUsername = new TextBox();
            TextBox txtGrade = new TextBox();
            Button btnAdd = new Button();
            ListView lBox = new ListView();

            //POS
            txtUsername.Location = new Point(0, 10);
            txtGrade.Location = new Point(0, 40);
            btnAdd.Location = new Point(0, 80);           
            lBox.Location = new Point(120, 0);

            //ListView props
            lBox.HeaderStyle = ColumnHeaderStyle.Clickable;
            lBox.View = View.Details;
            lBox.Size = new Size(200, 200);

            //Modify the whole LView sorting so both are synced.
            lBox.ColumnClick += new ColumnClickEventHandler((o, e) =>
            {
                lBox.ListViewItemSorter = new ListViewItemComparer(e.Column);
            });

            lBox.Columns.Add("Name");
            lBox.Columns.Add("Grade");

            this.Controls.Add(txtUsername);
            this.Controls.Add(txtGrade);
            this.Controls.Add(btnAdd);
            this.Controls.Add(lBox);

            btnAdd.Text = "Add";

            //Add a new Student object upon click (Inherits from ListViewItem)
            btnAdd.Click += new EventHandler((o, e) =>
            {
                try
                {
                    lBox.Items.Add(new Student(txtUsername.Text, Convert.ToSingle(txtGrade.Text)));
                    lBox.Refresh();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Incorrect input.");
                }
            });

        }
    }
}