[英]How do I make a ListBox refresh its item text?
我正在为那些还没有意识到像ListBox
这样的控件不必包含字符串的人做一个例子。 他一直在存储格式化的字符串并跳过复杂的解析箍以从ListBox
中取回数据,我想向他展示有更好的方法。
我注意到,如果我将 object 存储在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
我认为问题可能出在使用字段并尝试实现INotifyPropertyChanged ,但这没有效果。 (我使用字段的原因是因为它是一个示例,我不想添加与我正在演示的主题无关的几十行。)
老实说,我以前从未尝试过像这样更新项目; 过去我一直在添加/删除项目,而不是编辑它们。 所以我从来没有注意到我不知道如何使这项工作。
那么我错过了什么?
当我需要一个更新的列表框时,我使用这个 class。
更新列表中的 object,然后调用任一包含的方法,具体取决于您是否有可用的索引。 如果要更新列表中包含的 object,但没有索引,则必须调用 RefreshItems 并更新所有项目。
public class RefreshingListBox : ListBox
{
public new void RefreshItem(int index)
{
base.RefreshItem(index);
}
public new void RefreshItems()
{
base.RefreshItems();
}
}
lstBox.Items[lstBox.SelectedIndex] = lstBox.SelectedItem;
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);
}
}
}
}
typeof(ListBox).InvokeMember("RefreshItems",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod,
null, myListBox, new object[] { });
在列表框的数据源和数据源属性之间使用数据源属性和 BindingSource object。 然后刷新它。
更新添加示例。
像这样:
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
如果您从 ListBox 派生,则可以调用 RefreshItem 受保护的方法。 只需在您自己的类型中重新公开此方法即可。
public class ListBox2 : ListBox {
public void RefreshItem2(int index) {
RefreshItem(index);
}
}
然后更改您的设计器文件以使用您自己的类型(在本例中为 ListBox2)。
如果您使用如下绘制方法:
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);
}
传感器是我的 class。
因此,如果我在某处更改 class Color
,您可以简单地将其更新为:
int temp = listBoxName.SelectedIndex;
listBoxName.SelectedIndex = -1;
listBoxName.SelectedIndex = temp;
Color
会更新,只是另一种解决方案:)
这有点不专业,但它确实有效。 我刚刚删除并添加了该项目(也再次选择了它)。 该列表是根据“显示和更改”属性排序的,所以对我来说也很好。 副作用是引发了额外的事件(索引更改)。
if (objLstTypes.SelectedItem != null)
{
PublisherTypeDescriptor objType = (PublisherTypeDescriptor)objLstTypes.SelectedItem;
objLstTypes.Items.Remove(objType);
objLstTypes.Items.Add(objType);
objLstTypes.SelectedItem = objType;
}
我对 vb.net 不太了解,但在 C# 中,您应该使用数据源,然后通过调用listbox.bind()
来绑定它就可以了。
如果 objLstTypes 是您的 ListBox 名称使用 objLstTypes.Items.Refresh(); 希望这有效...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.