0

使用 .NET 4.0,我有一个主机应用程序,它解析一个 csv 文件,对每一行数据进行对象化,并通过 WCF 回调将其作为一个类型返回给我的客户端。这部分工作正常。当我尝试将该类型或类型集合添加到 MainWindow 中的 ObservableCollection 时,我开始遇到麻烦。

所以这...

 public class MyServiceCallback : IMyServiceCallback
    {
        //List<Location.LocationData> lastData = new List<Location.LocationData>();
        //Dictionary<string, Location.LocationData> lastData = new Dictionary<string,Location.LocationData>();
        //Network exposed Callback method which recieves Host/Client common data type
        //Note: Ought to be an interface and not a class type, but not needed for a small project
        public void OnCallback(Location.LocationData[] t)
        {
            //if(t.Where(x=>x.Frequency == lastData[
            //foreach (Location.LocationData d in t)
            //{
            //    lastData.Add(d.Frequency, d);
            //}
            //Call static method on MainWindow to pass the collection of LocationData to UI bound LocationList
            if(!(t.Length == 0))
            Client.MainWindow.SetLocationList(t.ToList());            
        }
    }

从 WCF 主机调用并 SetLocation(t.ToList()) 调用此...

public partial class MainWindow : Window
    {

private static MTObservableCollection<Location.LocationData> locationList = new MTObservableCollection<Location.LocationData>();

public static MTObservableCollection<Location.LocationData> LocationList
{
     get { return locationList; }
     set { locationList = value; }
} 

public static void SetLocationList(List<Location.LocationData> hostPushedLocationData)
        {
            //Clear previous location data
            LocationList.Clear();

            System.Threading.Thread.SpinWait(1);

            //Add the pushed data to the bound collection to be displayed
            hostPushedLocationData.ForEach(data => { LocationList.Add(data); System.Threading.Thread.SpinWait(1); });

        }
}

如果我使用的是普通的 ObservableCollection,这根本行不通,因为我无法从 WCF 线程更新集合。

如果我用这个扩展 ObservableCollection ......

public class MTObservableCollection<T> : ObservableCollection<T>
    {
        public override event NotifyCollectionChangedEventHandler CollectionChanged;
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            NotifyCollectionChangedEventHandler CollectionChanged = this.CollectionChanged;
            if (CollectionChanged != null)
                foreach (NotifyCollectionChangedEventHandler nh in CollectionChanged.GetInvocationList())
                {
                    DispatcherObject dispObj = nh.Target as DispatcherObject;
                    if (dispObj != null)
                    {
                        Dispatcher dispatcher = dispObj.Dispatcher;
                        if (dispatcher != null && !dispatcher.CheckAccess())
                        {
                            dispatcher.BeginInvoke(
                                (Action)(() => nh.Invoke(this,
                                    new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
                                DispatcherPriority.DataBind);
                            continue;
                        }
                    }
                    nh.Invoke(this, e);
                }
        }

    }

我在这里找到:我在哪里可以获得线程安全的 CollectionView?

我间歇性地收到此错误:

我在使用这个版本时遇到了异常,但在使用 Jonathan 提供的版本时却没有。有谁知道为什么会这样?这是我的 InnerException:引发此异常是因为名称为“OrdersGrid”的控件“System.Windows.Controls.DataGrid Items.Count:3”的生成器收到了与 Items 的当前状态不一致的 CollectionChanged 事件序列收藏。检测到以下差异:累计计数 2 与实际计数 3 不同。[累计计数为 (Count at last Reset + #Adds - #Removes since last Reset)

这在链接的帖子中提到。

我也经常收到此错误:索引超出范围。

如果有人可以帮助或指出我需要对这个集合扩展做些什么来解决这个问题,我将不胜感激。另外,如果我使用 .NET 4.5 而不是 4.0,这个问题会得到缓解吗?

万分感谢!

4

1 回答 1

0

您通过触发它们来推迟集合更改事件Dispatcher.BeginInvoke()。在您安排事件的时间和事件实际触发的时间之间,集合可能会发生多次更改。根据异常消息,听起来这正是正在发生的事情。

不要将变更事件安排在以后提出;他们应该立即被提升。

于 2013-11-04T21:02:37.583 回答