3

I have a Forms Application structured like this:

+--------------------------------------------------------------+
|      FormMain                                                |
|+------------------------+-----------------------------------+|
||  Panel ObjectCreation  |         Panel ObjectShow          ||
|+------------------------+-----------------------------------+|
|| Button AddObject()     | listPhones[selectedItem].Id       ||
|| ListBox listBoxPhones  |                                   ||
|+------------------------+-----------------------------------+|
+--------------------------------------------------------------+

Both Panels display two seperate Forms, FormObjectCreation and FormObjectShow. As soon as the ListBox fires the SelectedIndexChanged Event, the Panel ObjectShow gets updated.

However, afterwards, the listbox does not update anymore visually. It still functions though, still firing events. The listbox just seems to be frozen visually.

this is the AddObject() Function called by the button:

private void buttonAddObject_Click(object sender, EventArgs e)
{
    PhoneList.Add(new Phone(PhoneList.Count + 1));

    buttonSentTokensToPhone.Visible = true;
    listBoxPhones.DataSource = null;
    listBoxPhones.DataSource = PhoneList;
}

Here the Function handling the raised Event

private void listBoxPhones_SelectedIndexChanged(object sender, EventArgs e)
{
    this.FormMain.ShowCurrentPhone(PhoneList[listBoxPhones.SelectedIndex]);
}

// In FormMain.cs:
public void ShowCurrentPhone(Phone phone)
{
    panelPhone.Controls.Clear();
    FramePhone = new FrmPhone(this, phone) { Dock = DockStyle.Fill, TopLevel = false, TopMost = true };
    FramePhone.Name = "Phone " + phone.Id;
    FramePhone.FormBorderStyle = FormBorderStyle.None;
    panelPhone.Controls.Add(FramePhone);
    panelPhone.BorderStyle = BorderStyle.FixedSingle;
    FramePhone.Show();
}

I tried debugging it, however I couldn't find anything abnormal. I'm on .NET 4.7.2. Did anyone encounter this issue too?

UPDATE: Following Jimis comment below, I changed the PhoneList from a regular List to a BindingList. The code piece looks now like this:

private BindingList<Phone> PhoneList { get; set; }

private void buttonAddPhone_Click(object sender, EventArgs e)
{
        PhoneList.Add(new Phone(PhoneList.Count + 1));
        buttonSentTokensToPhone.Visible = true;
}

The ListBox is now working again as intended.

  • 1
    Why are you setting `listBoxPhones.DataSource = null;`? -- This: `panelPhone.Controls.Clear();` is one of the worst thing you can do in WinForms, especially when the Controls collection contains Forms (instead of UserControls, as it should be). -- It's also not clear why you create a new Form (UserControl) instead of updating the content. -- This code and its functionality needs to be reconsidered. -- I suggest you investigate how DataBinding works in this platform (starting from the use of a simple BindingList). – Jimi Apr 22 '22 at 12:29
  • `listBoxPhones.DataSource = null;` is how I learned it to do (i guess my teachers saw [this post](https://stackoverflow.com/a/17615334/9116813)), however the answer to your other questions is "I just don't know better" I rarely do anything with forms. This program is supposed to be an inhouse tech demo of a lib that has been made, not a product shipped or used for longer than 5 minutes. I was just curious of what is happening for that strange behaviour to occur. – Schattennarr Apr 25 '22 at 08:35
  • 1
    Your teacher(s) should have looked [right below that post](https://stackoverflow.com/a/17615338/7444103) (even though also the accepted answer is not correct, since the `DataSource` is set before `DisplayMember` - it should be set after, of course) -- The main problem is that you're resetting the DataSource for no reason (or, because the wrong tool is used - should be a BindingSource or a BindingList), which creates a new Form (should be a UserControl) which is also reset for no reason (at all) - also while the DataSource is replaced - it's never disposed, which causes a *race condition*[...] – Jimi Apr 25 '22 at 09:41
  • 1
    [...] It's just a matter of time before everything gets stuck in the motion. The use of simple data bindings and a UserControl (one) that is automatically updated when the SelectedItem changes would prevent this all from happening -- Keep in mind that here at SO we review the code, not whomever asks the question; hence, don't take it personally, any criticism is related to the code presented and the code alone. – Jimi Apr 25 '22 at 09:41
  • Don't worry; I didn't take anything personally :) Thanks for the explanations. I changed the code according to your criticism. – Schattennarr Apr 25 '22 at 10:40

1 Answers1

-1

i did this with a form and a usercontrol (not a form) and it works:

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public List<Phone> PhoneList { get; private set; }

        private void button1_Click(object sender, EventArgs e)
        {
            PhoneList = new List<Phone>();

            PhoneList.Add(new Phone(PhoneList.Count + 1));

           
            listBox1.DataSource = null;
            listBox1.DataSource = PhoneList;
            listBox1.DisplayMember = "Id";
        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listBox1!=null && listBox1.SelectedIndex>=0)
                ShowCurrentPhone(PhoneList[listBox1.SelectedIndex]);
        }
        public void ShowCurrentPhone(Phone phone)
        {
            panel2.Controls.Clear();
            UserControl1 FramePhone = new UserControl1(phone.Id);
            FramePhone.Name = "Phone " + phone.Id;
            panel2.Controls.Add(FramePhone);
            panel2.BorderStyle = BorderStyle.FixedSingle;
        }
    }

public class Phone
    {
        private int id;
        public string PonheNumber;

        public int Id { get => id; set => id = value; }

        public Phone(int id)
        {
            this.id = id;
            this.PonheNumber = "1111";
        }
    }
   

     public partial class UserControl1 : UserControl
    {
        private int id;
        public UserControl1(int id)
        {
            InitializeComponent();
            this.Id = id;
            label1.Text = Id.ToString();
        }

        public int Id { get => id; set => id = value; }
    }
Filippo
  • 56
  • 6
  • Still completely useless: `listBox1.DataSource = null;` (use a BindingList) -- Worst case scenario in WinForms: `panel2.Controls.Clear();` (the `Clear()` method doesn't *clear* anything, it just removes a reference from the collection, the object (UserControl or whatever) is still *alive* - put a Timer on it and test it); you need to dispose of a Control to remove it from the `Controls` collection. Useless anyway, the current object's output should be updated, you don't need to create a new object. -- Best if the output is updated using DataBindings. – Jimi Apr 22 '22 at 15:32
  • The focus of this code was to understand why the listbox was frozen in his code. – Filippo Apr 22 '22 at 16:06
  • 1
    You're trying to cure the effect instead of the cause, while the main problems are still there and these are going to present themselves in different forms. -- Using the `Clear()` method instead of disposing of a Control when a new instance is created is the kind of problem that dooms an application (sooner or later, maybe in your machine later). Some of the others I've already mentioned. – Jimi Apr 22 '22 at 16:15