10

这就是我所拥有的 - 一个 ListBox,其 ItemsSource 设置为 a ObservableCollection<T> - 其中 T 是我的自定义类,代表一个文件,仅包含 2 个 DependencyProperties:文件名和缩略图路径。- 列表框还定义了一个自定义 DataTemplate,以便在其下很好地显示图像和文件名。

列表框的目的是显示当前文件夹中的视频文件(在 TreeView 中选择),带有缩略图(异步生成;不是这个问题的一部分)。

因此,当我更改 TreeView 中的文件夹时,ObservableCollection 会被清除并再次填充,这会自动反映在 ListBox 项中。

问题出在:用户界面变得无响应,并且需要几秒钟才能更新。同样,缩略图在这里没有意义(我尝试禁用它们)。 我认为花费最多时间的是构建我的自定义类的 50-100 个实例,以及它们的视觉表示 - 它必须为每个实例初始化一个 Image 对象。但这只是我的猜测——您能否确认或排除这种可能性?

我开始认为ObservableCollection 可能不是这里的方法,因为从我阅读的内容和我尝试的内容来看,没有办法异步添加项目,至少如果这些项目是 DependencyObjects。我尝试使用 BackgroundWorker 创建我的类实例并将它们添加到 ProgressChanged 事件处理程序中的集合中,但它会引发异常(一些线程与依赖对象问题)。

有什么我想念的吗?或者我会通过简单地放弃 ObservableCollection 并编写一个好的旧 async for 循环来添加项目会更好吗?

4

3 回答 3

19

由于您ObservableCollection绑定到 UI,因此它是在 UI 线程上生成的,因此任何进一步的更新(删除/添加/清除)都必须在同一个 UI 线程上。它不允许来自另一个线程的更新。

但是,您可以做的是创建类的实例(或在后台线程上进行所有耗时的操作),一旦完成,使用Dispatcher您的 UI 线程在 ObservableCollection 中添加对象,如下所示 -

App.Current.Dispatcher.BeginInvoke((Action)delegate()
                          {
                              observableCollection.Add(instanceOfYourClass);
                          });

Dispatcher所做的是将操作放在其关联的线程上。因此,该项目将始终添加到 UI 线程,但可以在后台线程中创建。

这里有几个链接可能会让你继续前进 -从 BW 更新,另一个在这里

于 2012-10-14T10:53:33.423 回答
11

使用 .net 4.5,您可以使用 EnableCollectionSynchronization

 object lockObj = new object();
        BindingOperations.EnableCollectionSynchronization(yourObservableCollection, lockObj);
于 2016-07-01T14:38:51.153 回答
0

是的,这是一个老问题,我知道,但是像这样的问题已经结束了。我发现这在 IAsyncEnumerable 存在之前是可能的,但现在 IAsyncEnumerable 存在就更容易了。

ViewModel 类中的属性

public ObservableCollection<Card> Cards { get; set; }

ViewModel 构造函数

public CardViewModel(IDbContextFactory<CardContext> ccf)
{
    this.ctxFactory = ccf; //DB Context, using DI
    this.Cards = new ObservableCollection<Card>();

    Task.Run(async () =>
    {
        await foreach (Card card in GetAllCards())
        {
            this.Cards.Add(card);
        }
    });
}

private IAsyncEnumerable<Card> GetAllCards()
{
    CardContext cc = this.ctxFactory.CreateDbContext();
            
    return cc.Cards
        .Include(cc => cc.Edition)
        .Include(cc => cc.Site)
        .Include(cc => cc.Condition)
        .Include(cc => cc.Purchases)
        .Include(cc => cc.Trades)
        .AsNoTracking()
        .AsAsyncEnumerable();
}

卡片在视图中绑定到数据网格

ItemsSource="{Binding Cards}"

“卡片”一次添加到一个网格中,我可以在网格加载时与网格交互,并且应用程序不会冻结。

数据来自使用 EF Core 5 的数据库,这就是 CardContext,在这个例子中

于 2021-06-11T19:14:23.997 回答