2008-09-14 3 views
43

Я делаю пример для тех, кто еще не понял, что элементы управления, такие как ListBox, не должны содержать строки; он хранил форматированные строки и прыгал через сложные синтаксические обручи, чтобы вернуть данные из ListBox, и я хотел бы показать ему, что есть лучший способ.Как сделать ListBox обновить текст элемента?

Я заметил, что если у меня есть объект, сохраненный в ListBox, то обновите значение, которое влияет на ToString, ListBox не обновляет себя. Я попытался позвонить Refresh и Update на элемент управления, но не работает. Вот код примера я использую, это требует, чтобы перетащить ListBox и кнопку на форму:

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 между источником данных и свойством datasource в списке. Затем обновите это.

обновление добавленный пример.

Как так:

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]). Обновить(); Получение «скрытого» объекта из 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.Refresh(); Надеюсь, что это сработает ...

+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 будет обновлять, только одно решение :)

Смежные вопросы