如何使 ListView 在后台更新并且在 ItemsSource 更新时不冻结 UI?

How to make ListView update at background and not freez UI when ItemsSource updated?

我有一个 ListView:

 <ListView ItemsSource="{Binding Students, IsAsync=True}">             
     <ListView.View>
         <GridView>
             <!--Some view things -->
         </GridView>
     </ListView.View>
 </ListView>

这是我的 ViewModel 中的 Students

public ICollection<Student> Students
{
    get
    {
        return _students;

    }
    set
    {
        _students = value;
        OnPropertyChanged(() => this.Students);
    }
}

我正在更新 Students 这样的一些任务(当用户在另一个 TreeView 中选择某些内容时我正在更新 SourceState):

private State _sourceState;

public State SourceState
{
    get
    {
        return _sourceState;
    }
    set
    {
        _sourceState = value;
        OnSourceStateChanged();
        OnPropertyChanged(() => this.SourceState);
    }
}

private void OnSourceStateChanged()
{
    Task updateStudentFromSourceStateTask = new Task(() =>
    {
        Students = _stateService.GetAllStudents(_sourceState);
    });

    updateStudentFromSourceStateTask.Start();
}

问题是每当发生变化时 Students,UI 会冻结,直到 ListView 在新的 Students 中显示数据,我不知道如何让 ListView 刷新它的数据在后台线程中(我已经尝试 IsAsync=True 绑定但没有帮助)

你必须使用 "virtualizing"。

<ListView ItemsSource="{Binding Students}">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Vertical" />
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>

    <ListView.Resources>
         <DataTemplate DataType="...">
             <Grid>
                    ...
<ListView/>

编辑:

也许您的问题在于来源类型以及您如何评估它。在我确实使用它的特定情况下,我的来源声明如下:

    public IEnumerable<MyElementType> Elements
    {
        get { return (IEnumerable<MyElementType>)GetValue(ElementsProperty); }
        set { SetValue(ElementsProperty, value); }
    }
    public static readonly DependencyProperty ElementsProperty =
        DependencyProperty.Register("Elements", typeof(IEnumerable<MyElementType>), typeof(MyUiUserControlType), new UIPropertyMetadata(null));

当我将新过滤器应用于更大的块时,刷新发生了。当填充了所有必须实际可见的元素时,虚拟化将显示并允许立即开始使用您的列表。 您的问题可能出在使用 ICollection 上。但这已经取决于您的代码隐藏要求。

发生这种情况是因为我正在使用 Mahapps.Metro 并且它使 ListView 不使用 VirtualizingStackPanel

使用Style="{DynamicResource VirtualisedMetroListView}解决的问题