使用ObservableCollection时如何阻止DataGrid闪烁?

时间:2014-10-10 20:09:11

标签: wpf observablecollection

我已经与WPFObservableCollection进行了很长时间的斗争,现在我需要一些帮助。

这是设置和要求

  • 使用MongoDB作为支持数据库
  • 在数据库中存储大量日志数据
  • UI必须能够在日志插入数据库时​​显示(实时)
  • UI DataGrid绑定到ObservableCollection
  • UI DataGrid是并且必须由于内存使用而被分页,并且具有数百万条记录
  • 查看日志时,如果创建并显示了新条目,则还必须删除一个条目;这只是因为分页和设置页面大小(50个日志条目一次只能显示)
  • 使用ActiveMQ发出新日志条目的信号

所以基本上这是一个滚动日志视图,其中一个条目进入,一个条目退出。我必须保持所选项目并实时显示更新(这就是我使用ObservableCollection的原因)。可以过滤日志并导航页面,因此我认为当有新的日志条目并显示时,最简单的方法是获取整个页面;这也可以让我获得以前可能错过的条目。

我对此有很多问题,包括在后台线程上更新集合的问题,最近的问题是DataGrid"闪烁"何时创建新条目。我假设闪烁是每次刷新整个集合引起的,但替代方案(手动添加和删除项目)要复杂得多,而且由于过滤的复杂性,我不愿意去那条路线和传呼。

是否有任何良好的模式或建议可以阻止这种情况和#34;闪烁"或者更好的方法来实现可实时更新的可过滤日志视图?

的Xaml

<DataGrid ItemsSource="{Binding Entries, IsAsync=True}"
      AutoGenerateColumns="False" IsReadOnly="True"
      CanUserSortColumns="False"
      EnableColumnVirtualization="True" EnableRowVirtualization="True"
      VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Timestamp" Binding="{Binding Timestamp}" />
        <DataGridTextColumn Header="From" Binding="{Binding MessageFrom}" />
        <DataGridTextColumn Header="To" Binding="{Binding MessageTo}" />
        <DataGridTextColumn Header="Type" Binding="{Binding MessageType}" />
    </DataGrid.Columns>
</DataGrid>

我使用的绑定的ViewModel代码

//option 1
public ViewModel() { this.Entries = new ObservableCollection<Model>(); }

public void UpdateData()
{
    this.Entries.Clear();
    foreach (Model m in FetchModels())
        this.Entries.Add(m);
}

public ObversableCollection<Model> Entries { get; private set; }

//option 2
private List<Model> m_Entries = new List<Model>();

public void UpdateData()
{
    this.m_Entries.Clear();
    this.m_Entries.AddRange(FetchModels());
    this.NotifyPropertyChanged(() => this.Entries);
}

public ObversableCollection<Model> Entries { get { return new ObservableCollection<Model>(this.m_Entries); } }

//option 3
public ViewModel() { this.Entries = new ObservableCollection<Model>(); }

public void UpdateData()
{
    var tmp = this.Entries;
    this.Entries = null;

    tmp.Clear();
    foreach (Model m in FetchModels())
        tmp.Add(m);

    this.Entries = tmp;
    this.NotifyPropertyChanged(() => this.Entries);
}

public ObversableCollection<Model> Entries { get; private set; }

一旦我记得我尝试过的更多内容,我就会发布它。

1 个答案:

答案 0 :(得分:0)

这是我想出来的,似乎工作得很好,虽然我不喜欢它,并认为我可能会倾向于上述评论中的Lee O建议;但与此同时,由于截止日期临近,这就是我所做的。 UpdateData是它自己的主题。

public void UpdateData()
{
    var items = this.m_Cache.All<Model>().OrderByDescending(x => x.Timestamp).Take(50).Skip(0).ToList();

    lock (this.m_Sync)
    {
        var toRemove = this.Entries.Except(items).ToList();
        var toAdd = items.Except(this.Entries).ToList();

        foreach (Model m in toAdd)
            this.Entries.Add(m);

        foreach (Model m in toRemove)
            this.Entries.Remove(m);
    }

    this.NotifyOfPropertyChange(() => this.TotalRecords);
}
相关问题