2008-09-14 27 views
43

我正在为一个还没有意识到像ListBox这样的控件不必包含字符串的人举个例子;他一直在存储格式化的字符串,并跳过复杂的解析环节,以获取数据返回ListBox,我想告诉他有更好的方法。如何使ListBox刷新其项目文本?

我注意到如果我有一个对象存储在ListBox然后更新影响ToString的值,ListBox不会自我更新。我尝试过在控件上调用RefreshUpdate,但都不起作用。下面是我使用的例子的代码,它需要你拖动列表框和一个按钮到窗体:

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的,但这没有效果。 (我使用字段的原因是因为它是一个例子,我不想添加与我正在演示的主题无关的几十行。)

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

那么我错过了什么?

回答

24

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); 
      } 
     } 
    } 
} 
9

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

更新添加示例。

像这样:

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 
+0

优秀。出于某种原因,WinForms中的数据绑定永远不会跳出我的解决方案,无论我在WPF中使用多少。 – OwenP 2008-09-15 14:08:03

+0

呵呵,它曾经比这更有趣。例如: ((CurrencyManager)this.BindingContext [ListBox1])。Refresh(); 从BindingContext获取“隐藏”对象,然后将其转换为货币经理。 尽管这是C#,因为我从来没有在VB.NET中这样做过。 – Quibblesome 2008-09-15 15:55:43

+0

这是一个很好的答案,但最终geno建议使用BindingList 会导致较少的工作。 – OwenP 2010-01-26 16:28:30

-1

我不知道很多关于vb.net,但在C#中,你应该使用的数据源,然后将其绑定通过调用listbox.bind()会做的伎俩。

+2

这就是互联网。使这个人对WinForm感兴趣。 – Quibblesome 2008-09-15 12:00:41

1

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

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

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

32

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

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

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

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

请注意,`RefreshItem`只有在设置了'DisplayMember`属性时才起作用。 – 2016-12-31 14:07:55

0

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

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

为什么倒票? – nawfal 2012-07-07 04:14:49

+0

这将始终将选定的项目放在ListBox的末尾! – 2016-12-31 13:52:56

-3

如果objLstTypes是你的ListBox的名字 使用 objLstTypes.Items。刷新(); 希望这个工程...

+0

没有刷新方法。 – 2010-01-18 18:10:37

29
lstBox.Items[lstBox.SelectedIndex] = lstBox.SelectedItem; 
16
typeof(ListBox).InvokeMember("RefreshItems", 
    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, 
    null, myListBox, new object[] { }); 
0

如果你使用像一个抽奖方法:

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); 
} 

传感器是我的课。

所以,如果我改变类Color的地方,你可以简单地更新为:

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

而且Color会更新,只是另一种解决方案:)