更新ObservableCollection时UI会冻结

时间:2018-02-22 23:36:49

标签: c# wpf mvvm

我知道,关于这个主题已经有很多线程,但到目前为止我无法找到解决这个问题的方法。

首先,这是我的ItemsControl

<ScrollViewer Style="{StaticResource ScrollViewer}" VerticalScrollBarVisibility="Visible" MaxHeight="475">
<ItemsControl ItemsSource="{Binding CurrentSelectedItems}"  Margin="0 10 0 0">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <controls:ItemControl />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

为了简单起见,ItemsSource ItemsControl属性绑定到ObservableCollection类型的ItemViewModel

ItemViewModel包含大约25个属性和一些Prism DelegateCommands

ItemsControl顶部还有一些按钮可以更改CurrentSelectedItems的内容。由于这些项目有时总共多达300个,因此更新UI需要一些时间。在这种情况下,应用程序是 - 原因 - 冻结。

有没有办法不冻结UI和e.G.显示微调/加载消息?

提前致谢

修改 controls:ItemControl是一个简单的自定义控件,包含大约5个Labels和3个相当小的Images

3 个答案:

答案 0 :(得分:1)

尽管有其他答案,但没有办法避免这种情况。

WPF是SPA(单线程单元),意味着必须由UI线程创建和拥有任何UI对象。当你有很多UI元素要构建和渲染时,UI线程会很忙。

显示UI加载动画的解决方案也不正确,因为此动画也将位于UI线程上,即已经忙于创建和呈现UI集合的线程。

只需确保后台线程上的任何处理 IS ,并让UI管理自己。

答案 1 :(得分:0)

获取WPF工具包并使用BusyIndi​​cator。这将在您的控件顶部弹出一个窗口,其中有一个移动的忙碌指示器。您也可以使用它提供自定义消息。

答案 2 :(得分:0)

您可以使用任务来更新UI,但它需要一个List参数。要做到这一点:

// create an async method
private async void PopulateItems() {
   // use task to populate the items
   await Task.Run(() => {
      for (var item in CurrentSelectedItems) {
          this.Dispatcher.Invoke(() => yourItemCollectionControl.Add(item));
      }
   });
}