Как мне сделать ListBox обновить текст его элемента? - PullRequest
43 голосов
/ 14 сентября 2008

Я делаю пример для кого-то, кто еще не осознал, что элементы управления типа 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 , но это не дало никакого эффекта. (Причина, по которой я использую поля, заключается в том, что это пример, и мне не хочется добавлять несколько десятков строк, которые не имеют ничего общего с темой, которую я демонстрирую.)

Честно говоря, я никогда не пробовал обновлять элементы на месте, как это раньше; В прошлом я всегда добавлял / удалял элементы, а не редактировал их. Поэтому я никогда не замечал, что не знаю, как заставить это работать.

Так чего мне не хватает?

Ответы [ 10 ]

33 голосов
/ 15 сентября 2008

Я использую этот класс, когда мне нужно обновить список.

Обновите объект в списке и затем вызовите любой из включенных методов, в зависимости от того, имеется ли у вас индекс или нет. Если вы обновляете объект, который содержится в списке, но у вас нет индекса, вам придется вызвать RefreshItems и обновить все элементы.

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

    public new void RefreshItems()
    {
        base.RefreshItems();
    }
}
29 голосов
/ 26 ноября 2010
lstBox.Items[lstBox.SelectedIndex] = lstBox.SelectedItem;
24 голосов
/ 25 января 2010

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);
            }
        }
    }
}
16 голосов
/ 08 января 2011
typeof(ListBox).InvokeMember("RefreshItems", 
  BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod,
  null, myListBox, new object[] { });
9 голосов
/ 14 сентября 2008

Используйте свойство источника данных и объект 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
1 голос
/ 15 сентября 2008

Если вы наследуете от ListBox, существует защищенный метод RefreshItem, который вы можете вызвать. Просто повторно предоставьте этот метод в вашем собственном типе.

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

Затем измените ваш дизайнерский файл, чтобы использовать ваш собственный тип (в данном случае, ListBox2).

0 голосов
/ 12 марта 2015

Если вы используете метод рисования, например:

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 обновится, просто другое решение :)

0 голосов
/ 15 июня 2009

Если objLstTypes - ваше имя ListBox использование objLstTypes.Items.Refresh (); Надеюсь, это работает ...

0 голосов
/ 30 мая 2009

Это немного непрофессионально, но работает. Я просто удалил и добавил элемент (также выбрал его снова). Список был отсортирован в соответствии со свойством «отображено и изменено», поэтому, опять же, это было хорошо для меня. Побочным эффектом является то, что возникает дополнительное событие (индекс изменен).

if (objLstTypes.SelectedItem != null)
{
 PublisherTypeDescriptor objType = (PublisherTypeDescriptor)objLstTypes.SelectedItem;
 objLstTypes.Items.Remove(objType);
 objLstTypes.Items.Add(objType);
 objLstTypes.SelectedItem = objType;
}
0 голосов
/ 14 сентября 2008

Я не знаю много о vb.net, но в C # вы должны использовать источник данных, а затем связать его с помощью вызова listbox.bind().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...