如果一个元素被更改,如何更新ListBox c#

本文关键字:何更新 更新 ListBox 一个 元素 如果 | 更新日期: 2023-09-27 18:16:00

嗨,

我在使用ListBox.DataSource和INotifyPropertyChanged接口时有点吃力。我已经查看了几篇关于这个问题的帖子,但我不知道如果绑定BindingList的元素发生了更改,如何更新ListBox的视图。

我基本上想在内容解析后更改IndexItem的颜色。

以下是我表格中的相关电话:

btn_indexAddItem.Click += new EventHandler(btn_indexAddItem_Click);
lst_index.DataSource = Indexer.Items;
lst_index.DisplayMember = "Url";
lst_index.DrawItem += new DrawItemEventHandler(lst_index_DrawItem);
private void btn_indexAddItem_Click(object sender, EventArgs e)
{
    Indexer.AddSingleURL(txt_indexAddItem.Text);
}
private void lst_index_DrawItem(object sender, DrawItemEventArgs e)
{
    IndexItem item = lst_index.Items[e.Index] as IndexItem;
    if (item != null)
    {
        e.DrawBackground();
        SolidBrush brush = new SolidBrush((item.hasContent) ? SystemColors.WindowText : SystemColors.ControlDark);
        e.Graphics.DrawString(item.Url, lst_index.Font, brush, 0, e.Index * lst_index.ItemHeight);
        e.DrawFocusRectangle();
    }
}

Indexer.cs:

class Indexer
{
    public BindingList<IndexItem> Items { get; }
    private object SyncItems = new object();
    public Indexer()
    {
        Items = new BindingList<IndexItem>();
    }
    public void AddSingleURL(string url)
    {
        IndexItem item = new IndexItem(url);
        if (!Items.Contains(item))
        {
            lock (SyncItems)
            {
                Items.Add(item);
            }
            new Thread(new ThreadStart(() =>
            {
                // time consuming parsing
                Thread.Sleep(5000);
                string content = item.Url;
                lock (SyncItems)
                {
                    Items[Items.IndexOf(item)].Content = content;
                }
            }
            )).Start();
        }
    }
}

IndexItem.cs

class IndexItem : IEquatable<IndexItem>, INotifyPropertyChanged
{
    public int Key { get; }
    public string Url { get; }
    public bool hasContent { get { return (_content != null); } }
    private string _content;
    public string Content {
        get
        {
            return (hasContent) ? _content : "empty";
        }
        set
        {
            _content = value;
            ContentChanged();
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void ContentChanged()
    {
        if (this.PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Content"));
        }
    }
    public IndexItem(string url)
    {
        this.Key = url.GetHashCode();
        this.Url = url;
    }
    public override bool Equals(object obj)
    {
        return Equals(obj as IndexItem);
    }
    public override int GetHashCode()
    {
        return Key;
    }
    public bool Equals(IndexItem other)
    {
        if (other == null) return false;
        return (this.Key.Equals(other.Key)) ||
            ((hasContent || other.hasContent) && (this._content.Equals(other._content)));
    }
    public override string ToString()
    {
        return Url;
    }
}

有什么问题以及如何解决的想法吗?我将感谢任何提示。。。

如果一个元素被更改,如何更新ListBox c#

在我看来,控件在引发该项的ListChanged事件时应该重新绘制。这将迫使它这样做:

lst_index.DrawItem += new DrawItemEventHandler(lst_index_DrawItem);
Indexer.Items.ListChanged += Items_ListChanged;
private void Items_ListChanged(object sender, ListChangedEventArgs e)
{
    lst_index.Invalidate(); // Force the control to redraw when any elements change
}

那为什么它还不这么做呢?好吧,列表框似乎只在DisplayMember和INotifyPropertyChanged事件都已更改的情况下调用DrawItem。所以这也起作用:

lock (SyncItems)
{
    // Hacky way to do an Invoke
    Application.OpenForms[0].Invoke((Action)(() =>
    {
        Items[Items.IndexOf(item)].Url += " "; // Force listbox to call DrawItem by changing the DisplayMember
        Items[Items.IndexOf(item)].Content = content;
    }));
}

请注意,仅在Url上调用PropertyChanged是不够的。该值必须实际更改。这告诉我listbox正在缓存这些值-(

(使用VS2015 REL测试(