这就是我所拥有的
- 将ItemsSource设置为ObservableCollection<T>
的ListBox
- 其中T是我的表示文件的自定义类,只包含2个DependencyProperties:Filename和ThumbnailPath。
- 列表框还定义了自定义DataTemplate,以便在其下很好地显示图像和文件名。
列表框的目的是显示当前文件夹中的视频文件(在TreeView中选择),缩略图(异步生成;不是此问题的一部分)。
因此,当我更改TreeView中的文件夹时,ObservableCollection将被清除并再次填充,这将自动反映在ListBox项目中。
问题在于:UI变得无法响应,更新需要几秒钟。同样,缩略图在这里没有意义(我尝试禁用它们)。 我认为花费最多时间的是构建我自定义类的50-100个实例及其可视化表示 - 它必须为每个实例初始化一个Image对象。但这只是我的猜测 - 你能否确认或排除这种可能性?
我开始认为 ObservableCollection可能不是这里的方式,因为根据我的阅读和我尝试过的一点,没有办法异步添加项目,至少如果这些items是DependencyObjects。我尝试使用BackgroundWorker创建我的类实例,并将它们添加到ProgressChanged事件处理程序中的集合中,但它会引发异常(某些线程与依赖项对象问题)。
有什么东西我不见了吗?或者通过简单地抛弃ObservableCollection并编写一个好的旧异步for循环来添加项目,我会更好吗?
答案 0 :(得分:14)
由于您的ObservableCollection
绑定到UI,因此它会在UI线程上生成,因此任何进一步的更新(删除/添加/清除)都必须位于同一UI线程上。它不允许来自另一个线程的更新。
但是,您可以做的是创建类的insance(或在后台线程上执行所有耗时的操作),完成后,使用您的UI线程的Dispatcher
添加ObservableCollection中的对象,如下所示: / p>
App.Current.Dispatcher.BeginInvoke((Action)delegate()
{
observableCollection.Add(instanceOfYourClass);
});
Dispatcher做的是将操作放在其关联的线程上。因此,该项将始终添加到UI线程上,但可以在后台线程中创建。
以下几条链接可能会让您前进 - Updating from BW和其他here
答案 1 :(得分:7)
使用.net 4.5,您可以使用EnableCollectionSynchronization
object lockObj = new object();
BindingOperations.EnableCollectionSynchronization(yourObservableCollection, lockObj);
答案 2 :(得分: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,在这个例子中