【问题标题】:How to make ListView update at background and not freez UI when ItemsSource updated?当 ItemsSource 更新时,如何在后台更新 ListView 而不是冻结 UI?
【发布时间】:2015-08-03 03:46:12
【问题描述】:

我有一个 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 在后台线程中刷新它的数据(我试过 @987654329 @ 在绑定中,但没有帮助)

【问题讨论】:

  • 您要一次性替换整个集合,这可能会影响 UI 性能。您如何将其切换到具有实现 INPC 的学生实例的 ObservableCollection。然后,当您希望更新它们时,您可以遍历新旧列表并根据需要进行更新(属性值、删除实例、添加新实例等)。

标签: c# wpf listview mvvm binding


【解决方案1】:

你必须使用“虚拟化”。

<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。但这已经取决于您的代码隐藏要求。

【讨论】:

  • 在这种情况下,它不会填充冻结 UI 的 ListView。可能填充您的源本身。
  • 如果我删除 ItemsSource="{Binding Students}" 什么都不会冻结
  • 我正在使用INotifyPropertyChanged
【解决方案2】:

发生这种情况是因为我正在使用 Mahapps.Metro,这使得 ListView 不能使用 VirtualizingStackPanel

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-28
    • 2010-11-02
    • 2018-12-22
    • 1970-01-01
    • 2018-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多