programing

동일한 컬렉션에 서로 다른 필터가 있는 WPF 다중 컬렉션 보기

oldcodes 2023. 5. 9. 22:58
반응형

동일한 컬렉션에 서로 다른 필터가 있는 WPF 다중 컬렉션 보기

저는 an을 사용하고 있습니다.ObservableCollection둘이서ICollectionView여러 필터에 사용할 수 있습니다.

하나는 특정 유형별로 메시지를 필터링하는 것이고, 다른 하나는 체크된 메시지를 카운트하는 것입니다.메시지 필터와 메시지 수는 정상적으로 작동하지만 확인을 해제하면 메시지가 목록에서 사라집니다(카운트는 계속 작동 중).

그나저나 글이 길어서 미안해요, 관련된 모든 것을 포함하고 싶었어요.

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" />

스크린샷: 여기에 이미지 설명 입력

코드:

/* 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
}

체크 해제 기능에 대한 코드

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

대답은 이 정확한 문제를 해결하는 데 도움이 되었습니다.정적CollectionViewSource.GetDefaultView(coll)메소드는 지정된 컬렉션에 대해 항상 동일한 참조를 반환하므로 동일한 참조에 여러 컬렉션 뷰를 기반으로 하는 것은 역효과를 낳습니다.보기를 다음과 같이 인스턴스화합니다.

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

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

filteredView가 sourceCollection(이 예에서는 messageList)을 관찰하지 못하는 문제로 어려움을 겪고 있는 사용자를 위해 다음을 수행합니다.

저는 다음과 같은 해결책을 가지고 왔습니다.

ICollectionView filteredView = new CollectionViewSource { Source=messageList }.View;
messageList.CollectionChanged += delegate { filteredView.Refresh(); };

따라서 소스의 CollectionChanged 이벤트가 발생할 때마다 필터링된 View가 새로 고쳐집니다.물론 다음과 같이 구현할 수도 있습니다.

messageList.CollectionChanged += messageList_CollectionChanged;

private void messageList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    filteredView.Refresh(); 
}

특정 속성에 대한 필터링이 필요한 경우 속성 변경 이벤트를 사용하는 것이 좋습니다.

언급URL : https://stackoverflow.com/questions/16634194/wpf-multiple-collectionview-with-different-filters-on-same-collection

반응형