35

나는 ObservableCollection에 2 개의 ICollectionView을 다른 필터로 사용하고 있습니다.WPF 동일한 컬렉션에 다른 필터가있는 여러 CollectionView

하나는 메시지를 일부 유형으로 필터링하기위한 것이고, 하나는 확인 된 메시지를 계산하기위한 것입니다. 메시지 필터와 메시지 수는 정상적으로 작동하지만 확인을 취소하면 메시지가 목록에서 사라집니다 (수는 여전히 작동 중입니다)).

BTW 긴 게시물을 보내서 죄송합니다. 모든 관련 자료를 포함하고 싶습니다.

XAML 코드 :

<!-- Messages List --> 
<DockPanel Grid.Row="1" 
      Grid.Column="0" 
      Grid.ColumnSpan="3" 
      Height="500"> 
    <ListBox Name="listBoxZone" 
      ItemsSource="{Binding filteredMessageList}" 
      Background="Transparent" 
      BorderThickness="0"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
     <CheckBox Name="CheckBoxZone" 
        Content="{Binding text}" 
        Tag="{Binding id}" 
        Unchecked="CheckBoxZone_Unchecked" 
        Foreground="WhiteSmoke" 
        Margin="0,5,0,0" 
        IsChecked="{Binding isChecked}" /> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
    </ListBox> 
</DockPanel> 
<Button Content="Test Add New" 
     Grid.Column="2" 
     Height="25" 
     HorizontalAlignment="Left" 
     Margin="34,2,0,0" 
     Click="button1_Click" /> 
<Label Content="{Binding checkedMessageList.Count}" 
     Grid.Column="2" 
     Height="25" 
     Margin="147,2,373,0" 
     Width="20" 
     Foreground="white" /> 

스크린 샷 : enter image description here

코드 : 않은 체에 대한

/* ViewModel Class */ 
public class MainViewModel : INotifyPropertyChanged 
{ 

    // Constructor 
    public MainViewModel() 
    { 
     #region filteredMessageList 
     // connect the ObservableCollection to CollectionView 
     _filteredMessageList = CollectionViewSource.GetDefaultView(messageList); 
     // set filter 
     _filteredMessageList.Filter = delegate(object item) 
     { 
      MessageClass temp = item as MessageClass; 

      if (selectedFilter.Equals(AvailableFilters.All)) 
      { 
       return true; 
      } 
      else 
      { 
       return temp.filter.Equals(_selectedFilter); 
      } 
     }; 
     #endregion 

     #region checkedMessageList 
     // connect the ObservableCollection to CollectionView 
     _checkedMessageList = CollectionViewSource.GetDefaultView(messageList); 
     // set filter 
     _checkedMessageList.Filter = delegate(object item) { return (item as MessageClass).isChecked; }; 
     #endregion 
    } 

    // message List 
    private ObservableCollection<MessageClass> _messageList = 
      new ObservableCollection<MessageClass>(); 
    public ObservableCollection<MessageClass> messageList 
    { 
     get { return _messageList; } 
     set { _messageList = value; } 
    } 

    // CollectionView (filtered messageList) 
    private ICollectionView _filteredMessageList; 
    public ICollectionView filteredMessageList 
    { 
     get { return _filteredMessageList; } 
    } 

    // CollectionView (filtered messageList) 
    private ICollectionView _checkedMessageList; 
    public ICollectionView checkedMessageList 
    { 
     get { return _checkedMessageList; } 
    } 

    // SelectedFilter property 
    private AvailableFilters _selectedFilter = AvailableFilters.All; // Default is set to all 
    public AvailableFilters selectedFilter 
    { 
     get { return _selectedFilter; } 
     set 
     { 
      _selectedFilter = value; 
      RaisePropertyChanged("selectedFilter"); 
      _filteredMessageList.Refresh(); // refresh list upon update 
     } 
    } 

    // FilterList (Convert Enum To Collection) 
    private List<KeyValuePair<string, AvailableFilters>> _AvailableFiltersList; 
    public List<KeyValuePair<string, AvailableFilters>> AvailableFiltersList 
    { 
     get 
     { 
      /* Check if such list available, if not create for first use */ 
      if (_AvailableFiltersList == null) 
      { 
       _AvailableFiltersList = new List<KeyValuePair<string, AvailableFilters>>(); 
       foreach (AvailableFilters filter in Enum.GetValues(typeof(AvailableFilters))) 
       { 
        string Description; 
        FieldInfo fieldInfo = filter.GetType().GetField(filter.ToString()); 
        DescriptionAttribute[] attributes = 
           (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); 

        /* if not null get description */ 
        if (attributes != null && attributes.Length > 0) 
        { 
         Description = attributes[0].Description; 
        } 
        else 
        { 
         Description = string.Empty; 
        } 

        /* add as new item to filterList */ 
        KeyValuePair<string, AvailableFilters> TypeKeyValue = 
           new KeyValuePair<string, AvailableFilters>(Description, filter); 

        _AvailableFiltersList.Add(TypeKeyValue); 
       } 
      } 
      return _AvailableFiltersList; 
     } 
    } 

    #region Implement INotifyPropertyChanged 
    public event PropertyChangedEventHandler PropertyChanged; 
    public void RaisePropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
    #endregion 
} 

코드 CK 기능

private void CheckBoxZone_Unchecked(object sender, RoutedEventArgs e) 
{ 
    CheckBox chkZone = (CheckBox)sender; 
    ucSystemMessageVM.checkedMessageList.Refresh(); 
} 
+0

Dave이 답변은 그리 많지 않지만 길을 인도하는 데 도움이 될 수 있습니다. 최근 WPF 계약 작업을하면서 필터, 페이징, 정렬에 대한 올바른 솔루션을 찾지 못했습니다. 나는이 일반적인 클래스를 만들었다. 네가 그것에 대해 찌르기를 좋아할 것 같아. http://www.origin1.com/downloads/PagedObservableCollection.txt. 분명히 내선을 변경하십시오. – origin1tech

답변

68

This answer이 정확한 문제를 도와주었습니다. static CollectionViewSource.GetDefaultView(coll) 메서드는 항상 지정된 컬렉션에 대해 동일한 참조를 반환하므로 동일한 컬렉션에 여러 컬렉션 뷰를 배치하면 비생산적인 결과를 가져옵니다.

ICollectionView filteredView = new CollectionViewSource { Source=messageList }.View; 

다른보기와 독립적으로보기를 필터링/정렬/그룹화 할 수 있습니다. 그런 다음 필터링을 적용 할 수 있습니다.

나는 몇 달이 지났으므로 지금까지는 문제를 해결했을 것이라고 알고 있지만 같은 문제가있을 때이 질문을 건너 뛰었으므로 대답을 추가 할 것입니다.

+4

고마워, 그게 내가 달성 할 수 없었고 큰 못생긴 해결 방법으로 인한 결과는 매우 유용합니다. – drtf

+0

나는이 방법에 문제가 있습니다. filteredView는 messageList를 관찰하지 않는 것처럼 보이므로 어떤 소스 콜렉션에 대해서도 반응하지 않습니다 –