8

I have the class TestClass that has ToString overriden (it returns Name field). I have instances of TestClass added into ListBox and at certain point I need to change Name of one of this instances, how then I can refresh it's text in ListBox?

using System;
using System.Windows.Forms;

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

        private void Form1_Load(object sender, EventArgs e)
        {
            listBox1.Items.Add(new TestClass("asd"));
            listBox1.Items.Add(new TestClass("dsa"));
            listBox1.Items.Add(new TestClass("wqe"));
            listBox1.Items.Add(new TestClass("ewq"));
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ((TestClass)listBox1.Items[0]).Name = "123";
            listBox1.Refresh(); // doesn't help
            listBox1.Update(); // same of course
        }
    }

    public class TestClass
    {
        public string Name;

        public TestClass(string name)
        {
            this.Name = name;
        }

        public override string ToString()
        {
            return this.Name;
        }
    }
}

5 Answers 5

25

try

listBox1.Items[0] = listBox1.Items[0];
Sign up to request clarification or add additional context in comments.

Comments

8

I have encountered this same issue and tried all sorts of different ways to tr y to get the displayed text of an item to actually reflect the underlying item value. After going through all the available properties I found this to be the simplest. lbGroupList.DrawMode = DrawMode.OwnerDrawFixed; lbGroupList.DrawMode = DrawMode.Normal; It triggers the appropriate events within the control to update the displayed text.

1 Comment

For others venturing this far, this solution works great, and unlike Martin's answer it can be used even if you have your listbox data populated through the DataSource property
3

Your Testclass needs to implement INotifyPropertyChanged

public class TestClass : INotifyPropertyChanged
{
    string _name;

    public string Name
    {
        get { return _name;}
        set 
        {
              _name = value;
              _notifyPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void _notifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));  
    }

    public TestClass(string name)
    {
        this.Name = name;
    }

    public override string ToString()
    {
        return this.Name;
    }
}

However this only works if you use Columns that do not rely on the ToString() but bind the property Name

This can be done by altering your code:

somewhere in class declare

BindingList<TestClass> _dataSource = new BindingList<TestClass>();

In initializeComponent write

listBox1.DataSource = _dataSource;

Then do all operations on _dataSource instead of Listbox.

Comments

2

You could use a BindingList:

        items = new BindingList<TestClass>( );
        listBox1.DataSource = items;
        listBox1.DisplayMember = "_Name";

Then to refresh the list call:

        items.ResetBindings( );

edit: Also don't forget to create a get Property for Name

      public string _Name
    {
        get { return Name; }
        set { Name= value; }
    }

Comments

0

I use the following code:

public static void RefreshItemAt (ListBox listBox, int itemIndex)
{
    if (itemIndex >= 0)
    {
        Rectangle itemRect = listBox.GetItemRectangle(itemIndex);
        listBox.Invalidate(itemRect);
        listBox.Update();
    }
}

1 Comment

didn't work for me, had to use item = item strategy. Loved the idea tho.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.