【问题标题】:How to update a ListBox if an element was changed c#如果元素已更改 c# 如何更新 ListBox
【发布时间】:2016-01-02 06:50:35
【问题描述】:

嗨,

我在使用 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;
    }
}

任何想法出了什么问题以及如何解决它?我会很感激任何提示...

【问题讨论】:

    标签: c# winforms listbox inotifypropertychanged bindinglist


    【解决方案1】:

    在我看来,控件在引发该项目的 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 事件是从 UI 线程引发的,那么列表框似乎只调用 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 是不够的。该值必须实际改变。这告诉我列表框正在缓存这些值。 :-(

    (使用 VS2015 REL 测试)

    【讨论】:

    • 它有效,你。缓存一直很烦人:D,所以我会坚持第一个解决方案。
    猜你喜欢
    • 2014-07-26
    • 2011-07-14
    • 2021-04-21
    • 1970-01-01
    • 1970-01-01
    • 2011-11-28
    • 1970-01-01
    • 2012-12-04
    • 2014-07-27
    相关资源
    最近更新 更多