2015-06-18 5 views
2

Я ObservableCollection переплетены в dataGrid и теперь я хочу, чтобы отфильтровать представленные данные, я вижу, что мне нужно использовать ICollectionView, но я не уверен, как добавить ICollectionView с моим MVVM рисунком.Фильтрация ObservableCollection с ICollectionView

Мой код выглядит упрощены следующие:

public class MainViewModel : ViewModelBase , IBarcodeHandler 
{ 
    public ObservableCollection<TraceDataItem> TraceItemCollectionViewSource { get; set; } 
} 

Мой XAML

<Window xmlns:controls="clr-namespace:Mentor.Valor.vManage.RepairStation.Controls" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      <DataGrid Grid.Row="2" ColumnWidth="*" ItemsSource="{Binding TraceItemCollectionViewSource , Mode=TwoWay , UpdateSourceTrigger=PropertyChanged}" RowStyle="{StaticResource TraceRowStyle}" IsReadOnly="True" Name="TraceDataGrid" Margin="5,5,5,5" Padding="5,5,5,5" AutoGenerateColumns="False"> 
    </Window> 

Как я могу добавить ICollectionView здесь, чтобы применить фильтрацию к виду?

ответ

5

Вам потребуется:

public class MainViewModel : ViewModelBase, IBarcodeHandler 
{ 
    public ICollectionView TraceItemCollectionView 
    { 
     get { return CollectionViewSource.GetDefaultView(TraceItemCollectionViewSource); } 
    } 

    public ObservableCollection<TraceDataItem> TraceItemCollectionViewSource { get; set; } 
} 

затем, где-то в коде (возможно в конструкторе) добавить фильтр:

TraceItemCollectionView.Filter = o => 
{ 
    var item = (TraceDataItem) o; 

    //based on item, return true if it should be visible, or false if not 

    return true; 
}; 

И в XAML, вам нужно будет изменить привязка к свойству TraceItemCollectionView.

+0

@NightWalker Да. Я обновил свой ответ. – Andrew

+0

поэтому каждый раз, когда я меняю TraceItemCollectionViewSource мне нужно RaisePropertyChanged на TraceItemCollectionView, чтобы уведомить пользовательский интерфейс? –

+0

@NightWalker Да, так и есть. Однако вся точка ObservableCollection заключается в том, что вам не нужно ее менять. – Andrew

0

A CollectionView не всегда является лучшим решением. вы также можете отфильтровать свою коллекцию с помощью простого LinQ. Возьмем этот простой пример:

public ObservableCollection<TraceDataItem> FilteredData 
{ 
    get 
    { 
     return new ObservableCollection<TraceDataItem>(YourUnfilteredCollection.Where(
      i => MeetsFilterRequirements(i))); 
    } 
} 

private bool MeetsFilterRequirements(TraceDataItem item) 
{ 
    return item.SomeProperty == someValue || item is SomeType; 
} 

Красота этого метода заключается в том, что вы можете добавить сложные требования к фильтрации. Одно замечание: всякий раз, когда какие-либо свойства в этом методе изменяются, вам нужно позвонить NotifyPropertyChanged("FilteredData"), чтобы убедиться, что пользовательский интерфейс будет соответствующим образом обновлен.

+0

Это приведет к компиляции времени исключения. «Где» возвращает IEnumerable, а не коллекцию. – Andrew

+0

Хороший вопрос, спасибо ... обновил мой код. – Sheridan

+4

Неплохое редактирование, на мой взгляд. Вам лучше вернуть IEnumerable. Если вы новичок каждый раз, какова цель ObservableCollection? – Paparazzi

0

Вы можете вызвать фильтр обратного вызова из командной строки и разоблачить View свойство от CollectionViewSource:

public class ViewModel: INotifyPropertyChanged 
{ 
    private CollectionViewSource data = new CollectionViewSource(); 
    private ObservableCollection<Child> observableChilds = new ObservableCollection<Child>(); 

    public ViewModel() 
    { 
     var model = new Model(); 
     model.ChildList.Add(new Child { Name = "Child 1" }); 
     model.ChildList.Add(new Child { Name = "Child 2" }); 
     model.ChildList.Add(new Child { Name = "Child 3" }); 
     model.ChildList.Add(new Child { Name = "Child 4" }); 
     //Populate ObservableCollection 
     model.ChildList.ToList().ForEach(child => observableChilds.Add(child)); 

     this.data.Source = observableChilds; 
     ApplyFilterCommand = new DelegateCommand(OnApplyFilterCommand); 
    } 

    public ICollectionView ChildCollection 
    { 
     get { return data.View; } 
    } 

    public DelegateCommand ApplyFilterCommand { get; set; } 

    private void OnApplyFilterCommand() 
    { 
     data.View.Filter = new Predicate<object>(x => ((Child)x).Name == "Child 1"); 
     OnPropertyChanged("ChildCollection"); 
    } 
} 

//Sample Model used 
public class Model 
{ 
    public Model() 
    { 
     ChildList = new HashSet<Child>(); 
    } 

    public ICollection<Child> ChildList { get; set; } 
} 

public class Child 
{ 
    public string Name { get; set; } 
} 

//View 
<ListBox ItemsSource="{Binding Path = ChildCollection}" > 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <Label Content="{Binding Name}"/> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

<Button Command="{Binding ApplyFilterCommand}"/> 
Смежные вопросы