如何使ListBox刷新其项目文本?

时间:2023-01-13 09:59:04

I'm making an example for someone who hasn't yet realized that controls like ListBox don't have to contain strings; he had been storing formatted strings and jumping through complicated parsing hoops to get the data back out of the ListBox and I'd like to show him there's a better way.

我正在为一个尚未意识到像ListBox这样的控件不必包含字符串的人做一个例子;他一直在存储格式化的字符串并跳过复杂的解析箍以从ListBox中取回数据,我想告诉他有更好的方法。

I noticed that if I have an object stored in the ListBox then update a value that affects ToString, the ListBox does not update itself. I've tried calling Refresh and Update on the control, but neither works. Here's the code of the example I'm using, it requires you to drag a listbox and a button onto the form:

我注意到如果我有一个存储在ListBox中的对象然后更新一个影响ToString的值,则ListBox不会自行更新。我试过在控件上调用Refresh和Update,但都不起作用。这是我正在使用的示例的代码,它要求您将列表框和按钮拖到窗体上:

Public Class Form1

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
        MyBase.OnLoad(e)

        For i As Integer = 1 To 3
            Dim tempInfo As New NumberInfo()
            tempInfo.Count = i
            tempInfo.Number = i * 100
            ListBox1.Items.Add(tempInfo)
        Next
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        For Each objItem As Object In ListBox1.Items
            Dim info As NumberInfo = DirectCast(objItem, NumberInfo)
            info.Count += 1
        Next
    End Sub
End Class

Public Class NumberInfo

    Public Count As Integer
    Public Number As Integer

    Public Overrides Function ToString() As String
        Return String.Format("{0}, {1}", Count, Number)
    End Function
End Class

I thought that perhaps the problem was using fields and tried implementing INotifyPropertyChanged, but this had no effect. (The reason I'm using fields is because it's an example and I don't feel like adding a few dozen lines that have nothing to do with the topic I'm demonstrating.)

我想也许问题是使用字段并尝试实现INotifyPropertyChanged,但这没有任何效果。 (我使用字段的原因是因为它是一个例子,我不想添加几十行与我正在演示的主题无关。)

Honestly I've never tried updating items in place like this before; in the past I've always been adding/removing items, not editing them. So I've never noticed that I don't know how to make this work.

老实说,我以前从未尝试过更新这样的物品;在过去,我一直在添加/删除项目,而不是编辑它们。所以我从来没有注意到我不知道如何使这项工作。

So what am I missing?

那么我错过了什么?

10 个解决方案

#1


24  

BindingList handles updating the bindings by itself.

BindingList处理自己更新绑定。

using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace TestBindingList
{
    public class Employee
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }

    public partial class Form1 : Form
    {
        private BindingList<Employee> _employees;

        private ListBox lstEmployees;
        private TextBox txtId;
        private TextBox txtName;
        private Button btnRemove;

        public Form1()
        {
            InitializeComponent();

            FlowLayoutPanel layout = new FlowLayoutPanel();
            layout.Dock = DockStyle.Fill;
            Controls.Add(layout);

            lstEmployees = new ListBox();
            layout.Controls.Add(lstEmployees);

            txtId = new TextBox();
            layout.Controls.Add(txtId);

            txtName = new TextBox();
            layout.Controls.Add(txtName);

            btnRemove = new Button();
            btnRemove.Click += btnRemove_Click;
            btnRemove.Text = "Remove";
            layout.Controls.Add(btnRemove);

            Load+=new EventHandler(Form1_Load);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _employees = new BindingList<Employee>();
            for (int i = 0; i < 10; i++)
            {
                _employees.Add(new Employee() { Id = i, Name = "Employee " + i.ToString() }); 
            }

            lstEmployees.DisplayMember = "Name";
            lstEmployees.DataSource = _employees;

            txtId.DataBindings.Add("Text", _employees, "Id");
            txtName.DataBindings.Add("Text", _employees, "Name");
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            Employee selectedEmployee = (Employee)lstEmployees.SelectedItem;
            if (selectedEmployee != null)
            {
                _employees.Remove(selectedEmployee);
            }
        }
    }
}

#2


32  

I use this class when I need to have a list box that updates.

当我需要一个更新的列表框时,我使用这个类。

Update the object in the list and then call either of the included methods, depending on if you have the index available or not. If you are updating an object that is contained in the list, but you don't have the index, you will have to call RefreshItems and update all of the items.

更新列表中的对象,然后调用其中一个包含的方法,具体取决于您是否有索引。如果要更新列表中包含的对象,但没有索引,则必须调用RefreshItems并更新所有项目。

public class RefreshingListBox : ListBox
{
    public new void RefreshItem(int index)
    {
        base.RefreshItem(index);
    }

    public new void RefreshItems()
    {
        base.RefreshItems();
    }
}

#3


29  

lstBox.Items[lstBox.SelectedIndex] = lstBox.SelectedItem;

#4


16  

typeof(ListBox).InvokeMember("RefreshItems", 
  BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod,
  null, myListBox, new object[] { });

#5


9  

Use the datasource property and a BindingSource object in between the datasource and the datasource property of the listbox. Then refresh that.

在数据源和列表框的datasource属性之间使用datasource属性和BindingSource对象。然后刷新它。

update added example.

更新添加的示例。

Like so:

像这样:

Public Class Form1

    Private datasource As New List(Of NumberInfo)
    Private bindingSource As New BindingSource

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
        MyBase.OnLoad(e)

        For i As Integer = 1 To 3
            Dim tempInfo As New NumberInfo()
            tempInfo.Count = i
            tempInfo.Number = i * 100
            datasource.Add(tempInfo)
        Next
        bindingSource.DataSource = datasource
        ListBox1.DataSource = bindingSource
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        For Each objItem As Object In datasource
            Dim info As NumberInfo = DirectCast(objItem, NumberInfo)
            info.Count += 1
        Next
        bindingSource.ResetBindings(False)
    End Sub
End Class

Public Class NumberInfo

    Public Count As Integer
    Public Number As Integer

    Public Overrides Function ToString() As String
        Return String.Format("{0}, {1}", Count, Number)
    End Function
End Class

#6


1  

If you derive from ListBox there is the RefreshItem protected method you can call. Just re-expose this method in your own type.

如果从ListBox派生,则可以调用RefreshItem保护方法。只需在您自己的类型中重新公开此方法即可。

public class ListBox2 : ListBox {
    public void RefreshItem2(int index) {
        RefreshItem(index);
    }
}

Then change your designer file to use your own type (in this case, ListBox2).

然后更改您的设计器文件以使用您自己的类型(在本例中为ListBox2)。

#7


0  

It's little bit unprofessional, but it works. I just removed and added the item (also selected it again). The list was sorted according to "displayed and changed" property so, again, was fine for me. The side effect is that additional event (index changed) is raised.

这有点不专业,但它确实有效。我刚删除并添加了该项目(也再次选中)。该列表是根据“显示和更改”属性排序的,所以再次对我来说很好。副作用是引发附加事件(索引已更改)。

if (objLstTypes.SelectedItem != null)
{
 PublisherTypeDescriptor objType = (PublisherTypeDescriptor)objLstTypes.SelectedItem;
 objLstTypes.Items.Remove(objType);
 objLstTypes.Items.Add(objType);
 objLstTypes.SelectedItem = objType;
}

#8


0  

If you use a draw method like:

如果您使用如下绘制方法:

private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
    e.DrawBackground();
    e.DrawFocusRectangle();

    Sensor toBeDrawn = (listBox1.Items[e.Index] as Sensor);
    e.Graphics.FillRectangle(new SolidBrush(toBeDrawn.ItemColor), e.Bounds);
    e.Graphics.DrawString(toBeDrawn.sensorName, new Font(FontFamily.GenericSansSerif, 14, FontStyle.Bold), new SolidBrush(Color.White),e.Bounds);
}

Sensor is my class.

传感器是我的班级。

So if I change the class Color somewhere, you can simply update it as:

因此,如果我在某处更改类Color,您只需将其更新为:

int temp = listBoxName.SelectedIndex;
listBoxName.SelectedIndex = -1;
listBoxName.SelectedIndex = temp;

And the Color will update, just another solution :)

而Color将更新,只是另一个解决方案:)

#9


-1  

I don't know much about vb.net but in C# you should use datasource and then bind it by calling listbox.bind() would do the trick.

我对vb.net了解不多,但在C#中你应该使用datasource然后通过调用listbox来绑定它.bind()可以解决问题。

#10


-3  

If objLstTypes is your ListBox name Use objLstTypes.Items.Refresh(); Hope this works...

如果objLstTypes是你的ListBox名称使用objLstTypes.Items.Refresh();希望这有效......

#1


24  

BindingList handles updating the bindings by itself.

BindingList处理自己更新绑定。

using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace TestBindingList
{
    public class Employee
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }

    public partial class Form1 : Form
    {
        private BindingList<Employee> _employees;

        private ListBox lstEmployees;
        private TextBox txtId;
        private TextBox txtName;
        private Button btnRemove;

        public Form1()
        {
            InitializeComponent();

            FlowLayoutPanel layout = new FlowLayoutPanel();
            layout.Dock = DockStyle.Fill;
            Controls.Add(layout);

            lstEmployees = new ListBox();
            layout.Controls.Add(lstEmployees);

            txtId = new TextBox();
            layout.Controls.Add(txtId);

            txtName = new TextBox();
            layout.Controls.Add(txtName);

            btnRemove = new Button();
            btnRemove.Click += btnRemove_Click;
            btnRemove.Text = "Remove";
            layout.Controls.Add(btnRemove);

            Load+=new EventHandler(Form1_Load);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _employees = new BindingList<Employee>();
            for (int i = 0; i < 10; i++)
            {
                _employees.Add(new Employee() { Id = i, Name = "Employee " + i.ToString() }); 
            }

            lstEmployees.DisplayMember = "Name";
            lstEmployees.DataSource = _employees;

            txtId.DataBindings.Add("Text", _employees, "Id");
            txtName.DataBindings.Add("Text", _employees, "Name");
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            Employee selectedEmployee = (Employee)lstEmployees.SelectedItem;
            if (selectedEmployee != null)
            {
                _employees.Remove(selectedEmployee);
            }
        }
    }
}

#2


32  

I use this class when I need to have a list box that updates.

当我需要一个更新的列表框时,我使用这个类。

Update the object in the list and then call either of the included methods, depending on if you have the index available or not. If you are updating an object that is contained in the list, but you don't have the index, you will have to call RefreshItems and update all of the items.

更新列表中的对象,然后调用其中一个包含的方法,具体取决于您是否有索引。如果要更新列表中包含的对象,但没有索引,则必须调用RefreshItems并更新所有项目。

public class RefreshingListBox : ListBox
{
    public new void RefreshItem(int index)
    {
        base.RefreshItem(index);
    }

    public new void RefreshItems()
    {
        base.RefreshItems();
    }
}

#3


29  

lstBox.Items[lstBox.SelectedIndex] = lstBox.SelectedItem;

#4


16  

typeof(ListBox).InvokeMember("RefreshItems", 
  BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod,
  null, myListBox, new object[] { });

#5


9  

Use the datasource property and a BindingSource object in between the datasource and the datasource property of the listbox. Then refresh that.

在数据源和列表框的datasource属性之间使用datasource属性和BindingSource对象。然后刷新它。

update added example.

更新添加的示例。

Like so:

像这样:

Public Class Form1

    Private datasource As New List(Of NumberInfo)
    Private bindingSource As New BindingSource

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
        MyBase.OnLoad(e)

        For i As Integer = 1 To 3
            Dim tempInfo As New NumberInfo()
            tempInfo.Count = i
            tempInfo.Number = i * 100
            datasource.Add(tempInfo)
        Next
        bindingSource.DataSource = datasource
        ListBox1.DataSource = bindingSource
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        For Each objItem As Object In datasource
            Dim info As NumberInfo = DirectCast(objItem, NumberInfo)
            info.Count += 1
        Next
        bindingSource.ResetBindings(False)
    End Sub
End Class

Public Class NumberInfo

    Public Count As Integer
    Public Number As Integer

    Public Overrides Function ToString() As String
        Return String.Format("{0}, {1}", Count, Number)
    End Function
End Class

#6


1  

If you derive from ListBox there is the RefreshItem protected method you can call. Just re-expose this method in your own type.

如果从ListBox派生,则可以调用RefreshItem保护方法。只需在您自己的类型中重新公开此方法即可。

public class ListBox2 : ListBox {
    public void RefreshItem2(int index) {
        RefreshItem(index);
    }
}

Then change your designer file to use your own type (in this case, ListBox2).

然后更改您的设计器文件以使用您自己的类型(在本例中为ListBox2)。

#7


0  

It's little bit unprofessional, but it works. I just removed and added the item (also selected it again). The list was sorted according to "displayed and changed" property so, again, was fine for me. The side effect is that additional event (index changed) is raised.

这有点不专业,但它确实有效。我刚删除并添加了该项目(也再次选中)。该列表是根据“显示和更改”属性排序的,所以再次对我来说很好。副作用是引发附加事件(索引已更改)。

if (objLstTypes.SelectedItem != null)
{
 PublisherTypeDescriptor objType = (PublisherTypeDescriptor)objLstTypes.SelectedItem;
 objLstTypes.Items.Remove(objType);
 objLstTypes.Items.Add(objType);
 objLstTypes.SelectedItem = objType;
}

#8


0  

If you use a draw method like:

如果您使用如下绘制方法:

private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
    e.DrawBackground();
    e.DrawFocusRectangle();

    Sensor toBeDrawn = (listBox1.Items[e.Index] as Sensor);
    e.Graphics.FillRectangle(new SolidBrush(toBeDrawn.ItemColor), e.Bounds);
    e.Graphics.DrawString(toBeDrawn.sensorName, new Font(FontFamily.GenericSansSerif, 14, FontStyle.Bold), new SolidBrush(Color.White),e.Bounds);
}

Sensor is my class.

传感器是我的班级。

So if I change the class Color somewhere, you can simply update it as:

因此,如果我在某处更改类Color,您只需将其更新为:

int temp = listBoxName.SelectedIndex;
listBoxName.SelectedIndex = -1;
listBoxName.SelectedIndex = temp;

And the Color will update, just another solution :)

而Color将更新,只是另一个解决方案:)

#9


-1  

I don't know much about vb.net but in C# you should use datasource and then bind it by calling listbox.bind() would do the trick.

我对vb.net了解不多,但在C#中你应该使用datasource然后通过调用listbox来绑定它.bind()可以解决问题。

#10


-3  

If objLstTypes is your ListBox name Use objLstTypes.Items.Refresh(); Hope this works...

如果objLstTypes是你的ListBox名称使用objLstTypes.Items.Refresh();希望这有效......