【问题标题】:Automatically refresh ICollectionView Filter自动刷新 ICollectionView 过滤器
【发布时间】:2013-07-18 03:26:17
【问题描述】:

有什么方法可以自动更新ICollectionView 上的过滤器,而无需在进行相关更改时调用Refresh()

我有以下几点:

[Notify]
public ICollectionView Workers { get; set; }

此属性中的 [Notify] 属性只是实现了INotifyPropertyChanged,但在这种情况下它似乎没有做任何事情。

Workers = new CollectionViewSource { Source = DataManager.Data.Workers }.View;

Workers.Filter = w =>
    {
        Worker worker = w as Worker;
        if (w == null)
            return false;
        return worker.Employer == this;
    };

在 XAML 中:

<TextBlock x:Name="WorkersTextBlock"
           DataContext="{Binding PlayerGuild}"
           FontFamily="Pericles"
           Text="{Binding Workers.Count,
                          StringFormat=Workers : {0},
                          FallbackValue=Workers : 99}" />

更新:看来使用ICollectionView 对我来说是必要的,所以我想重新讨论这个话题。我正在为这个问题添加一个赏金,其接收者将是任何可以提供一些关于如何实现不需要手动刷新的“放手”ICollectionView 的见解的人。在这一点上,我对任何想法都持开放态度。

【问题讨论】:

  • 好吧,考虑到该属性不是 BCL,它没有涵盖这种极端情况也就不足为奇了。实际上,WPF 中没有任何内容涵盖这种情况,因此您必须自己动手。过滤器属性不是 DP,即使它是,过滤器中的任何内容都不会触发更新事件。看起来你将不得不手动触发它。也许在过滤器的主体中?您可以通过闭包进行自我引用。查看 lambda,您必须将对 Refresh 的调用卸载到 Dispatcher,以便在应用过滤器后运行。呃,并添加一个布尔“brb更新”块
  • (没有更多的字符)看起来没有任何办法解决它,除了可能在过滤器期间扩展 CVS 和更新,并检查以确保您不会持续触发更新。为什么这不是 BCL 是有道理的,对吧?过滤器触发一个更新,它触发一个过滤器,然后就……
  • 感谢您的解释。看来我将手动执行此操作。
  • 好吧,抱有希望。根据历史和我的经验。如果它还没有接线,那么你通常必须自己接线。而且,如果你这样做了,请在下面添加答案并给自己一些道具!而且,如果你成功了,我会再次给你 +1。
  • 我对编程还很陌生,在这一点上,我不知道如何利用我所拥有的有限知识来实现​​这一目标。有一天,也许,但还没有。

标签: c# wpf icollectionview


【解决方案1】:

对于 .Net 4.5: 有一个新的接口可以帮助实现这个功能,叫做:ICollectionViewLiveShaping

来自MSDN link

启用实时排序、分组或过滤时,CollectionView 将重新排列数据在 CollectionView 中的位置,当 数据被修改。例如,假设应用程序使用 DataGrid 列出股票市场中的股票,股票按以下顺序排序 股票价值。如果在股票的 CollectionView 上启用了实时排序, 当股票的价值发生变化时,股票在 DataGrid 中的位置发生变化 变得大于或小于另一只股票的价值。

以上界面的更多信息: http://www.jonathanantoine.com/2011/10/05/wpf-4-5-%E2%80%93-part-10-live-shaping/


对于 .Net 4 及更低版本: 还有另一篇关于 SO QA 的帖子可能会对您有所帮助: CollectionViewSource Filter not refreshed when Source is changed

【讨论】:

【解决方案2】:

AFAIK 在ICollectionView 中没有内置支持来刷新基础源集合中的任何属性更改的集合。

但您可以继承 ListCollectionView 以将您自己的实现赋予 refresh collection on any property changed。示例 -

public class MyCollectionView : ListCollectionView
{
    public MyCollectionView(IList sourceCollection) : base(sourceCollection)
    {
        foreach (var item in sourceCollection)
        {
            if (item is INotifyPropertyChanged)
            {
                ((INotifyPropertyChanged)item).PropertyChanged +=
                                                  (s, e) => Refresh();
            }
        }
    }
}

你可以像这样在你的项目中使用它-

Workers = new MyCollectionView(DataManager.Data.Workers);

这可以在您的项目中重复使用,而不必担心在每个 PropertyChanged 上刷新集合。 MyCollectionView 会为你做到这一点automatically

如果您使用的是 .Net4.5,您可以使用 ICollectionViewLiveShaping 实现,如 here 所述。

我已经在此处发布了您的问题的实现部分 - Implementing ICollectionViewLiveShaping

该帖子中的工作代码 -

public ICollectionViewLiveShaping WorkersEmployed { get; set; }

ICollectionView workersCV = new CollectionViewSource
                         { Source = GameContainer.Game.Workers }.View;

ApplyFilter(workersCV);

WorkersEmployed = workersCV as ICollectionViewLiveShaping;
if (WorkersEmployed.CanChangeLiveFiltering)
{
    WorkersEmployed.LiveFilteringProperties.Add("EmployerID");
    WorkersEmployed.IsLiveFiltering = true;
}

【讨论】:

  • 嗯,有点。当一个新项目被添加到集合中时,它没有被正确处理,因为逻辑在构造函数中。我会尝试一下,看看我能做些什么。
  • 实际上,ICollectionViewLiveShaping 的这种实现也可以。当我尝试你的答案时,我不知道我最初做错了什么。再次感谢!
  • 如何监听嵌套属性?
  • 仅供参考:您不需要公开ICollectionViewLiveShaping,您可以保留ICollectionView,它仍然可以工作。只需投射到它并设置属性,它就会起作用。
猜你喜欢
  • 1970-01-01
  • 2012-01-10
  • 2013-05-17
  • 2016-04-07
  • 2010-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-09
相关资源
最近更新 更多