异步更新DataGrid的集合项时,为什么数据会消失

本文关键字:为什么 数据 消失 更新 DataGrid 集合 异步 | 更新日期: 2023-09-27 18:22:08

我有一个DataGrid,它绑定到使用Observable Collection的DataGridCollectionView。该系列包含约650多个项目,约20列。每60秒就会接收一个新的数据集合。将该数据与现有集合进行比较,然后根据需要添加、删除和更新项。对于更新,我正在进行以下操作:

private async void LoadData()
    {
        await RefreshData(TimeSpan.FromSeconds(100), cts.Token);
    }
private async Task RefreshData(TimeSpan interval, CancellationToken token)
    {
        // Get the writable properties for the ContingencyViewModel 
        var writableProperties = typeof(ContingencyViewModel).GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(p => p.CanWrite);
        while (!token.IsCancellationRequested)
        {
            var list = viewModel.Items;
            var cvs = GetItems();  // Service call that gets the updated collection
            var existingIds = list.Select(s => s.UniqueId).Distinct().ToList();
            var sourceIds = cvs.Select(s => s.UniqueId).Distinct().ToList();
            var toAdd = sourceIds.Except(existingIds).ToList();
            var toRemove = existingIds.Except(sourceIds).ToList();
            var toUpdate = existingIds.Intersect(sourceIds).ToList();
            var itemsToAdd = cvs.Where(x => toAdd.Contains(x.UniqueId)).ToList();
            var itemsToRemove = list.Where(x => toRemove.Contains(x.UniqueId)).ToList();
            var itemsToUpdate = list.Where(x => toUpdate.Contains(x.UniqueId)).ToList();
                // Add new items
                foreach (ItemViewModel item in itemsToAdd)
                {
                    list.Add(item);
                }
                // Remove dropped items
                foreach (ItemViewModel item in itemsToRemove)
                {
                    list.Remove(item);
                }
                // Update existing items
                foreach (ItemViewModel item in itemsToUpdate)
                {
                    // Get a reference to the Updated Item
                    var source = cvs.First(x => x.UniqueId == item.UniqueId);
                    // This works but locks the UI for a little bit
                    this.UpdateItem<ItemViewModel>(source, item, writableProperties);
                   // This also works but all the results in my grid disappear when I scroll or resize screen.  To get them back I have to actually Expand and Collapse groups.
                    /*
                    Action d = delegate()
                    {                        
                        this.UpdateItem<ItemViewModel>(source, item, writableProperties);
                    };
                    Dispatcher.CurrentDispatcher.InvokeAsync(d, DispatcherPriority.Normal, token);
                    */
                } 
                if (token.IsCancellationRequested)
                    token.ThrowIfCancellationRequested();
            if (interval > TimeSpan.Zero)
                await Task.Delay(interval, token);
        }
    }
private void UpdateItem<T>(T source, T target, IEnumerable<PropertyInfo> properties)
    {
        foreach (var p in properties)
        {
            var value = p.GetValue(source);
            p.SetValue(target, value);
        }  
    }

正如我所期望的那样,直接更新会滞后于UI,但无论何时滚动或调整窗口大小,尝试从另一个线程进行更新似乎都会导致数据消失。我所说的"消失"是指那些行在那里,但它们是空的。唯一能让它恢复的方法就是瓦解和扩大一个群体。我甚至尝试过对数据源进行刷新(这对我来说似乎是个坏主意,因为每次字段更新后都会调用它)。

为什么异步更新时数据会消失?有没有更好或更合适的方法来对绑定到数据网格的项目进行此类更新?

异步更新DataGrid的集合项时,为什么数据会消失

正如您所知,WPF遵循STA架构。因此,根据经验法则,所有的更新都应该在UI线程上完成。对于上述情况,可以使用Dispatcher:你可以在这里和这里阅读更多关于调度员的

理想情况下,您可以尝试以下操作:

ThreadStart start = delegate()
{
  // make your calls to the db
  Dispatcher.Invoke(DispatcherPriority.Normal, 
                    new Action<object>(UpdateCollection), 
                    new object[] { myData });
};
new Thread(start).Start();
private void UpdateCollection(object data)
{
   //iterate your collection and add the data as needed
}