【问题标题】:How do I make a ListBox refresh its item text?如何让 ListBox 刷新其项目文本?
【发布时间】:2010-09-08 20:27:35
【问题描述】:

我正在为尚未意识到 ListBox 之类的控件不必包含字符串的人做一个示例;他一直在存储格式化的字符串并跳过复杂的解析循环以从ListBox 中取回数据,我想向他展示有更好的方法。

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

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

那么我错过了什么?

【问题讨论】:

    标签: .net winforms user-interface


    【解决方案1】:

    在列表框的数据源和数据源属性之间使用数据源属性和 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
    

    【讨论】:

    • 优秀。出于某种原因,无论我在 WPF 中使用了多少,WinForms 中的数据绑定都不会成为我的解决方案。
    • 嘿,它曾经比这更有趣。类似于: ((CurrencyManager)this.BindingContext[ListBox1]).Refresh();从 BindingContext 中获取“隐藏”对象,然后将其转换为货币管理器。虽然这是 C#,因为我从未在 VB.NET 中这样做过。
    • 这是一个很好的答案,但最终 geno 建议使用 BindingList 会导致工作量减少。
    【解决方案2】:

    我对 vb.net 了解不多,但在 C# 中,您应该使用数据源,然后通过调用 listbox.bind() 绑定它就可以了。

    【讨论】:

    • 那是互联网。我认为这个人对 WinForm 感兴趣。
    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

      • 注意,RefreshItem 仅在设置了DisplayMember 属性时才有效。
      【解决方案5】:

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

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

      【讨论】:

      • 这将始终将所选项目放在列表框的末尾!
      【解决方案6】:

      如果 objLstTypes 是您的 ListBox 名称 采用 objLstTypes.Items.Refresh(); 希望这行得通...

      【讨论】:

        【解决方案7】:

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

        【讨论】:

        • 这实际上比当前接受的答案要少。壮丽的!我编辑了您的帖子以包含一个示例。
        • 我认为您实际上可以进一步改进。您可以将父绑定和子绑定应用于控件,这意味着您可以在没有 _SelectedIndexChanged 事件处理程序的情况下执行此操作。我忘记了确切的代码...... :(
        • 我已经更新了示例,删除了 SelectedIndexChanged 事件处理程序并在 Load 处理程序中替换为 2 个新行。 :)
        • 我使用的是常规列表,但我认为这不是问题所在,而是在其他地方寻找麻烦。谢谢!
        • 据我所知,这并没有解决实际更新所列项目文本的问题。
        【解决方案8】:
        lstBox.Items[lstBox.SelectedIndex] = lstBox.SelectedItem;
        

        【讨论】:

        • 这实际上是一个有效的答案!
        • 这个得到我的投票!简单,无需添加任何新的类或代码段即可完成。这就是我所需要的。
        • 请注意,如果您通过 DataSource 属性设置项目,这将不起作用。
        • 愚蠢的简单。很好的答案。
        【解决方案9】:
        typeof(ListBox).InvokeMember("RefreshItems", 
          BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod,
          null, myListBox, new object[] { });
        

        【讨论】:

        • 我发现这很有用:它可以用来使列表框动态刷新
        【解决方案10】:

        如果你使用如下的绘制方法:

        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 将更新,只是另一种解决方案:)

        【讨论】:

          猜你喜欢
          • 2012-05-27
          • 1970-01-01
          • 1970-01-01
          • 2010-09-29
          • 1970-01-01
          • 2023-03-28
          • 1970-01-01
          • 1970-01-01
          • 2012-09-21
          相关资源
          最近更新 更多