【问题标题】:Using LinQ to filter ObservableCollection使用 LinQ 过滤 ObservableCollection
【发布时间】:2015-07-12 12:43:29
【问题描述】:

我有一个 MVVM 应用程序,我正在尝试通过 LinQ 对我的 ObservableCollection 进行过滤,该 ObservableCollection 是从基于实体框架的数据库中获取的。

在视图模型中我有这个:

public class MenuListViewModel : BaseViewModelCollection<Menu>

{
    private string filterString;

    public string FilterString
    {
        get { return filterString; }
        set
        {
            if (Equals(value, filterString)) return;
            filterString = value;
            RaisePropertyChanged();
        }
    }

    //TODO problems with notification, filter doesn't work
    public ObservableCollection<Menu> FilteredItems
    {
        get
        {
            if (filterString == null) return Items; //Items is Observable Collection that contains every Item
            var query = Items.Where(x => x.Time.ToString().StartsWith(filterString));
            return new ObservableCollection<Menu>(query);
        }
    }

    public MenuListViewModel(MenuService menuService)
    {
        base.Service = menuService; //Using IoC to get service
    }
}

在 Xaml 中我有以下绑定:

 <TextBox x:Name="RecipeFilterBox" Margin="5,5,0,0" TextWrapping="Wrap" Text="{Binding FilterString, NotifyOnTargetUpdated=True}" Grid.Column="1" Height="47.07" VerticalAlignment="Top"/>

问题是当我在 TextBox 中写任何东西时,什么都没有改变。我知道 propertyChanged 事件有问题,但我真的不知道如何解决这个问题。如果您需要有关此应用的更多信息,请询问我。

编辑: FilteredItems 的 xaml 如下所示:

    <ListBox x:Name="MenuItemsListView" ItemsSource="{Binding FilteredItems}" SelectedItem="{Binding DeletedItem, Mode=OneWayToSource}" Foreground="#FFFFEDD3" FontFamily="Segoe Print" FontWeight="Bold" FontSize="18.667" Grid.ColumnSpan="3" Grid.Row="1" ItemContainerStyle="{DynamicResource ListBoxItemStyle1}" Style="{DynamicResource ListBoxStyle1}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Recipe.Name}" Width="255"/>
                    <TextBlock Width="175" Text="{Binding Time, Converter={StaticResource EnumTimeToItsDescriptionValueConverter}, Mode=OneWay}" />
                    <TextBlock Text="{Binding Date, StringFormat=dd.MM.yyyy}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

【问题讨论】:

标签: c# wpf linq mvvm observablecollection


【解决方案1】:

您可以使用ICollectionView 实现此目的。

使用FilteredItems 作为ICollectionView 的底层源并将ICollectionView 暴露给您的视图,而不是ObservableCollection&lt;Menu&gt;

使用过滤器委托提供过滤器逻辑

FilteredItems.Filter = item =>
{
    Menu m = item as Menu;
    return m.Time.ToString().StartsWith(FilterString);
}

FilterString 改变时调用FilterItems.Refresh();

这是一个例子:

public class MenuListViewModel : BaseViewModelCollection<Menu>
{
   public MenuListViewModel()
   {
      var data = new List<Menu> { some data ... }; // your real list of menus
      // initialize the collection view
      FilteredItems = CollectionViewSource.GetDefaultView(data);
      // apply filtering delegate
      FilteredItems.Filter = i =>
      {
         // This will be invoked for every item in the underlying collection 
         // every time Refresh is invoked
         if (string.IsNullOrEmpty(FilterString)) return true;
         Menu m = i as Menu;
         return m.Time.ToString().StartsWith(FilterString);
      };
   }

   private string filterString;
   public string FilterString
   {
       get { return filterString; }
       set
       {
           if (Equals(value, filterString)) return;
           filterString = value;
           FilteredItems.Refresh(); // tirggers filtering logic
           RaisePropertyChanged("FilterString"); 
       }
   }

    public ICollectionView FilteredItems { get; set; }
}

您还必须更改过滤器TextBox 上的UpdateSourceTrigger,以使其在每次用户更改文本时更新FilterString

Text="{Binding FilterString, UpdateSourceTrigger=PropertyChanged, ...}

【讨论】:

  • 我有很多新东西,你能更具体地说明如何在我的应用程序中应用它吗?
  • 我应该如何将 ICollectionView 添加到类中?我想,public ICollectionView FilteredItems = CollectionViewSource.GetDefaultView(Items);不是正确的方法。
  • @Dracke 我上传了一个完整的例子。希望这会有所帮助
  • 我现在有一个问题,我使用的是项目而不是数据,它是可观察的集合,它包含具有多个属性的菜单类。属性之一是时间。我如何强制过滤器中的 i 只关心时间?现在,我真的不知道它过滤了什么,但可能有一些参考。
  • @Dracke i 是基础集合中的一个项目,在您的情况下是一个 Menu 对象。只需投射它并使用它来提取您想要的属性。我已经更新了示例
【解决方案2】:

FilterString 设置器中添加RaisePropertyChanged("FilteredItems")FilteredItems 属性更改永远不会引发,因此绑定不会按您期望的方式工作。

【讨论】:

  • 我改变了 RaisePropertyChanged();在 FilterString 中 RaisePropertyChanged("FilteredItems");但过滤器仍然无法正常工作。 “FilteredItems”也加了下划线(可能是 resharper),表明 Explicit 参数传递给带有调用者信息属性的参数。
猜你喜欢
  • 2012-08-04
  • 1970-01-01
  • 2020-03-21
  • 2018-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-04
  • 2011-01-30
相关资源
最近更新 更多