WPF CollectionViewSource.Filter 性能与 DataTrigger

发布于 2024-12-01 13:06:04 字数 1101 浏览 0 评论 0原文

实体框架提供可跟踪实体,它们具有名为 ChangeTracker.State 的属性。使用它我们可以识别实体是否被删除。

在我们的列表中,我们不想显示已删除的实体。

哪个更快?

方法1:使用CollectionViewSource.Filter测试并删除记录

<CollectionViewSource Filter="ViewSource_Filter" />

private void ViewSource_Filter(object sender, FilterEventArgs e)
{
    var _Item = e.Item as ITrackableEntity;
    e.Accepted = _Item.ChangeTracker.State != ObjectState.Deleted;
}

方法2:将DataTrigger添加到ItemTemplate.DataTemplate以测试并隐藏项目

<DataTemplate.Resources>
    <Style TargetType="{x:Type DockPanel}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding ChangeTracker.State}">
                <DataTrigger.Value>
                    <entities:ObjectState>Deleted</entities:ObjectState>
                </DataTrigger.Value>
                <Setter Property="Visibility" Value="Collapsed"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</DataTemplate.Resources>

谢谢。

The Entity Framework provides Trackable Entities who have a property called ChangeTracker.State. Using this we can identify if an Entity is Deleted.

In our list we do NOT want to show Deleted entities.

Which is faster?

Method 1: Using a CollectionViewSource.Filter to Test and remove the Record

<CollectionViewSource Filter="ViewSource_Filter" />

private void ViewSource_Filter(object sender, FilterEventArgs e)
{
    var _Item = e.Item as ITrackableEntity;
    e.Accepted = _Item.ChangeTracker.State != ObjectState.Deleted;
}

Method 2: Adding a DataTrigger to the ItemTemplate.DataTemplate to Test and Hide the Item

<DataTemplate.Resources>
    <Style TargetType="{x:Type DockPanel}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding ChangeTracker.State}">
                <DataTrigger.Value>
                    <entities:ObjectState>Deleted</entities:ObjectState>
                </DataTrigger.Value>
                <Setter Property="Visibility" Value="Collapsed"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</DataTemplate.Resources>

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

荒路情人 2024-12-08 13:06:04

假设这个问题涉及到一个ItemsControl,我个人喜欢基于collectionview的过滤器。

原因...

  1. 它的过滤是在ViewModel手中。因此,每当它想要刷新集合视图时,它都会再次重新过滤。

  2. 如果 ChangeTracker.State 属性仅在 UI 的整个生命周期中填充且未更新,则集合视图将仅在渲染时过滤一次。另一方面,DataTriggers 将等待 ChangeTracker.State 发生任何更改,这可能会发生,也可能不会发生。

  3. 应用此 CollectionView 的 ItemsControl 的交替项目行样式不会在数据触发器中正确生效,因为它只会隐藏项目,不会调整交替行样式,但 CollectionView 会预先排除这些项目。即,如果交替行需要为灰色背景,那么如果使用 DataTrigger,则可能会出现两个相邻行为灰色的情况。

  4. DataTriggers 仅对非虚拟化项目生效,因此滚动条启发式可能会出错,例如,如果滚动视图仅显示 10 个可见项目,并且源中有 90 个项目,但有 50 个项目在已删除 状态,除非我们滚动到它们,否则它们的数据触发器不会生效。因此在此期间滚动条将重新计算并闪烁以调整其实际滚动值。因此,我们可能有 100 个适用于滚动的项目,而实际上它只需要滚动到 50 个项目。

CollectionView 提供了 50 个项目来滚动视图。

因此,正是由于这一点,就性能而言,DataTrigger 将会更快,因为它仅适用于项目被去虚拟化(即引入滚动视图)时。但它可能会带来上述问题。

让我知道这是否有帮助。

Assuming that there is a ItemsControl involved in this problem, I personally like the collectionview based filter.

Reasons...

  1. Its filtering is in the hands of ViewModel. So whenever it wants to refresh the collection view it will re-filter again.

  2. If ChangeTracker.State property is only populated and not updated throughout the lifecycle of the UI, then the collection view will only filter once at rendering. DataTriggers on the other hand will wait for any changes to ChangeTracker.State which may / may not happen.

  3. Alternating Items Row styles for the ItemsControl for which this CollectionView is the applied, will not take correct effect with the data trigger, coz it will only hide the items and not adjust alternate row styles but collectionview will exclude the items beforehand itself. i.e. if alternate rows need to be of gray background then it may happen that two adjacent rows will be gray if DataTrigger is used.

  4. DataTriggers will take effect ONLY for non-vitualized items due to which the Scrollbar heuristics may get screwed e.g. if scroll view shows only 10 items visible and there are 90 items in the source but 50 are in Deleted state, their data trigger will not take effect unless we scroll to them. So during this the scrollbar will re-calculate and flicker for adjusting its actual scroll value. SO it may luk like we have 100 items applicable for scrolling whereas actually it only needs 50 items to scroll to.

CollectionView provides 50 items to scroll view before hand itself.

So exactaly due to this as far as performance goes, DataTrigger will be faster due to the fact that will apply only apply when the item is de-virtualized i.e. brought in the scroll view. But it may pose the above issues.

Let me know if this helps.

你的呼吸 2024-12-08 13:06:04

但 Loaded 事件可能包含您需要的信息。来自 MSDN:Loaded 事件在最终渲染之前、布局系统计算出渲染所需的所有值之后引发。已加载意味着包含元素的逻辑树是完整的,并且连接到提供 HWND 和渲染表面的表示源。我对此的解释是过滤器和触发器已被处理,但我并不肯定。卸载量不是最终数字,但我认为您会进行同类比较。但苹果可能仍然不是正确的比较。如果调试器能够遍历 XAML,那就太好了。由于调试器不遍历 XAML,我认为您无法直接测量触发器。最好的希望是测量页面。创建一个页面,除了一个困难的过滤器之外什么都没有。

    public MainWindow()
    {
        Debug.WriteLine(DateTime.Now.ToLongTimeString());
        InitializeComponent();
        Debug.WriteLine(DateTime.Now.ToLongTimeString());
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine(DateTime.Now.ToLongTimeString());

调试与直接执行不同,因此我会将这 3 次绑定到 TextBlocks。我还会与 XAML 中定义的过滤器进行比较。我的直觉是,两者都将如此之快,以至于很难知道其中的区别,但我猜过滤器更快。

But the Loaded event may have the information you need. From MSDN: The Loaded event is raised before the final rendering, but after the layout system has calculated all necessary values for rendering. Loaded entails that the logical tree that an element is contained within is complete, and connects to a presentation source that provides the HWND and the rendering surface. My interpretation of the is that filters and triggers have been processed but I am not positive. Unloaded is not a final number but I think you would be comparing apples to apples. But still apples may not be the right comparison. It would be so nice if the debugger walked the XAML. Since the debugger does not walk the XAML I just don't think you can directly measure the trigger. The best hope is to measure the page. Create a page with nothing but a difficult filter.

    public MainWindow()
    {
        Debug.WriteLine(DateTime.Now.ToLongTimeString());
        InitializeComponent();
        Debug.WriteLine(DateTime.Now.ToLongTimeString());
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine(DateTime.Now.ToLongTimeString());

Debug is not the same as straight execute so I would bind those 3 times to TextBlocks. And I would also compare with the filter defined in XAML. My gut feel is the are both going to be so fast that it is hard to know the difference but I would guess the filter is faster.

瞎闹 2024-12-08 13:06:04

方法 1 是正确答案。

Method 1 is the correct answer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文