【问题标题】:DataGrid not updating when items added to ObservableCollection in Silverlight将项目添加到 Silverlight 中的 ObservableCollection 时,DataGrid 未更新
【发布时间】:2011-08-18 12:04:51
【问题描述】:

我有一个与 WCF 服务交互的 Silverlight 应用程序。它定期从该服务接收要添加到列表的新项目,并且每个新元素都添加到 ObservableCollection 的末尾(每个新元素的 collection.Add())。

项目本身在收到后不会更改,并且项目的类继承 INotifyPropertyChanged,但是当我添加新项目(从 WCF 接收)时,DataGrid 不会更新。
我还在为 DataGrid 绑定使用自定义格式化程序,但我认为这不是问题,因为初始项集正确显示(第一次设置 ItemsSource 时)。

我预计会出现新元素,因为我已经确认 ObservableCollection 正在发出正确的添加事件。既然 ObservableCollection 是从 INotifyCollectionChanged 继承的,那它不应该更新 DataGrid 吗?

目前我找到的唯一解决方案是:

dataGrid.ItemsSource = null;
dataGrid.ItemsSource = collection;

关于如何更新它的任何想法?此方法会在很长一段时间内阻止 UI。
谢谢

更新:代码

在 WCF 回调事件中展开和提取元素:

// The ItemWrapper allows the Binding converter to be passed the entire trade object, rather than just each property.
ObservableCollection<ItemWrapper<ExpandedTrade>> pastTrades = new ObservableCollection<ItemWrapper<ExpandedTrade>>();
....

       // Extract and expand data - MinimalTrade is the data sent through WCF
       var convertedTrades = from MinimalTrade t in e.trades
                                  select new ItemWrapper<ExpandedTrade>(
                                      new ExpandedTrade(t,
                                          usernames.ContainsKey(t.UserToId) ? usernames[t.UserToId] : null, potentialWealth != null ? potentialWealth.CurrentWealth : null)); // Get name, otherwise null.
       // Data now expanded (to show full information like usernames
       // pastTrades is an observableCollection
            foreach (var trade in convertedTrades)
            {
                pastTrades.Add(trade);
            }
            OnNewMyTradeHistory(pastTrades);

OnNewMyTradeHistory 事件然后执行以下操作:

if (tradeHistory.ItemsSource == null) tradeHistory.ItemsSource = trades;

这只会将 ItemsSource 设置一次(到 ObservableCollection),并且会触发添加事件,但 UI 端没有发生任何事情。

WCF 回调可能发生在另一个线程中。

【问题讨论】:

  • 您是否绑定到依赖属性?
  • 这应该可以。您将不得不向我们展示更多代码。您如何将项目添加到您的收藏中?您能否提供一个非常精简的问题版本,您可以在此处完整提供吗?
  • 您是否在后台线程上更新数据网格源?我在使用某些后台线程时无法正确触发 PropertyChanged 事件
  • 我尝试在 UI 线程中运行更新和数据绑定(使用 UserControl 的调度程序),但同样的事情仍然发生。
  • INFO:我找到了解决方案,但 Stackoverflow 直到 5 小时后才让我发布答案。届时会这样做。解决方案是从 ItemWrapper 类中删除自定义 Equals() 方法。

标签: c# silverlight datagrid observablecollection


【解决方案1】:

我找到了解决办法!

我已经在 ItemWrapper 和 ExpandedTrade 中实现了 EqualsGetHashCodeToString 方法:

ItemWrapper.cs:(调用子类中的等价方法)

    public override bool Equals(object obj)
    {
        if(obj is T) return Quote.Equals(obj);
        if (obj is ItemWrapper<T>) return Quote.Equals(((ItemWrapper<T>)obj).Quote);
        return this == obj;
    }
    public override int GetHashCode() { return Quote.GetHashCode(); }
    public override string ToString() { return Quote.ToString(); }

ExpandedTrade.cs:

    public override bool Equals(object obj)
    {
        if (obj == null) return false;
        ExpandedQuote q = obj as ExpandedQuote;
        if (q == null) return false;
        return q.Id == Id;
    }

    public override int GetHashCode() { return Id; }

删除这些方法后,它起作用了。我想 DataGrid 正在某处测试相等性,并且不知何故返回了不正确的测试。 ID 是唯一的,但通过使用默认的引用相等测试,它现在可以工作了。

【讨论】:

    【解决方案2】:

    告诉我这个流程是否正确:

    • DataGrid.ItemsSource == null;
    • [更新]
      • 创建新的可观察集合:CollectionA
      • 获取项目并将其添加到 CollectionA
      • [事件]
        • DataGrid.ItemsSource == null -> ItemsSource = CollectionA
    • [更新]
      • 创建新的可观察集合:CollectionB
      • 获取项目并将其添加到 CollectionB
      • [事件]
        • DataGrid.ItemsSource != null -> 什么都不做
    • => DataGrid.ItemsSource == CollectionA?

    或者过去交易是一个只初始化一次的字段?括号和方法边界会有所帮助。

    【讨论】:

    • CollectionA is pastTrades,并且只初始化一次。所有新元素都添加到pastTradespastTrades 在构造函数中创建。我也可以通过使用调试器来确认这是有效的。如果我查看 Locals 窗口中的 tradeHistory.ItemsSource(在添加了 10 多个项目之后),我可以看到这 10 个新项目已进入作为 ItemsSource 的 ObservableCollection。调试器显示约 15 个元素,但 DataGrid 仅显示初始的约 5 个。
    • @neuropie:现在真的应该工作了。你能上传一个可靠地证明问题的项目吗?为此可能需要所有上下文...
    猜你喜欢
    • 2014-11-05
    • 1970-01-01
    • 2014-03-21
    • 1970-01-01
    • 1970-01-01
    • 2015-07-13
    • 2021-11-15
    • 1970-01-01
    • 2012-04-02
    相关资源
    最近更新 更多