입력 텍스트를 기반으로 콤보 상자 항목을 필터링하는 방법은 무엇입니까?
뷰 모델에서 항목을 제공하는 콤보 상자를 표시하고 싶습니다. 콤보 상자는 편집 가능해야합니다. 사용자가 현재 입력 한 텍스트를 기반으로 콤보 상자 항목을 필터링해야합니다.
주제에 대한 다양한 리소스에서 지적한 다음 솔루션을 적용하려고합니다 (예 : 해당 질문 , 해당 질문 , 해당 기사 , 해당 질문 , 해당 블로그 게시물 , 해당 튜토리얼 등).
- 내보기 모델은 항목에 대한 컬렉션보기를 제공합니다.
Text
콤보 상자의CustomText
속성을 뷰 모델 의 속성에 양방향 바인딩했습니다 .Filter
컬렉션 뷰 의 조건자는 표시 이름에CustomText
.CustomText
가 변경 되면Refresh
항목 컬렉션보기 의 메서드가 호출됩니다.
텍스트를 수정할 때마다 콤보 상자 드롭 다운 목록의 항목 목록이 업데이트 될 것으로 예상합니다. 불행히도 목록은 동일하게 유지됩니다.
내 Filter
술어에 중단 점을 넣으면 적중되지만 각 항목에 대해 항상 그런 것은 아닙니다.
다음은 최소한의 예입니다.
창용 XML :
<Window x:Class="ComboBoxFilterTest.MainWindow"
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"
xmlns:local="clr-namespace:ComboBoxFilterTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ComboBox
VerticalAlignment="Center"
ItemsSource="{Binding Items}"
DisplayMemberPath="Name"
IsEditable="True"
Text="{Binding CustomText}"
IsTextSearchEnabled="False"/>
</Grid>
</Window>
창의 코드 숨김 :
using System.Windows;
namespace ComboBoxFilterTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
}
그리고보기 모델 (여기서는 Item
일반적으로 다른 곳에 상주 하는 데이터 클래스 포함) :
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Data;
namespace ComboBoxFilterTest
{
public class MainViewModel : INotifyPropertyChanged
{
private sealed class Item
{
public int Id { get; set; }
public string Name { get; set; }
}
public MainViewModel()
{
Items = new CollectionView(items)
{
Filter = item =>
{
if (string.IsNullOrEmpty(customText))
{
return true;
}
if (item is Item typedItem)
{
return typedItem.Name.ToLowerInvariant().Contains(customText.ToLowerInvariant());
}
return false;
}
};
}
private readonly ObservableCollection<Item> items = new ObservableCollection<Item>
{
new Item{ Id = 1, Name = "ABC" },
new Item{ Id = 2, Name = "ABCD" },
new Item{ Id = 3, Name = "XYZ" }
};
public ICollectionView Items { get; }
private string customText = "";
public event PropertyChangedEventHandler PropertyChanged;
public string CustomText
{
get => customText;
set
{
if (customText != value)
{
customText = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CustomText)));
Items.Refresh();
}
}
}
}
}
기본적으로 나는 다른 질문에 설명 된 것과 똑같이하고 있다고 생각 하지만 분명히 내 경우에는 작동하지 않기 때문에 뭔가 여전히 다릅니다.
한 가지 약간의 차이점은 기본보기 CollectionViewSource.GetDefaultView
를 가져 오는 대신 동일한 컬렉션에 대해 서로 다른 필터링 된보기를 여러 개 갖고 싶기 때문에을 사용하지 않는다는 것 입니다.
A와 유의 해결 , 나는 물론 단지 자신을 항목의 적절하게 필터링 된 열거를 반환 할 수 있고마다 이러한 열거 속성에 대한 필터를 변경 속성 변경 이벤트를 발생. 그러나 컬렉션 뷰에 의존하는 것이 적절한 WPF 방법임을 이해하므로 "올바르게"수행하는 것이 좋습니다.
답변
경험하는 것과 같은 문제를 피하기 위해 권장되는 패턴 CollectionViewSource
은 바인딩 소스 로 사용 하는 것입니다.
문서에서도 언급했듯이 인스턴스를 CollectionView
수동으로 만들면 안됩니다 . 소스 컬렉션의 실제 유형에 따라 특수한 하위 유형을 사용해야합니다.
"
CollectionView
코드 에서이 클래스 [ ]의 개체를 만들면 안됩니다 . IEnumerable 만 구현하는 컬렉션에 대한 컬렉션보기를 만들려면 CollectionViewSource 개체를 만들고 Source 속성에 컬렉션을 추가 한 다음 View 속성에서 컬렉션보기를 가져옵니다. . " Microsoft 문서 : CollectionView
CollectionViewSource
내부적으로 유형 검사를 ICollectionView
수행하고 실제 소스 컬렉션에 적합한 적절 하게 초기화 된 구현을 만듭니다 . 기본보기가 충분하지 않은 경우 CollectionViewSource
XAML 또는 C #으로 생성되었는지 여부에 관계없이의 인스턴스를 가져 오는 데 권장되는 방법입니다 ICollectionView
.
public ICollectionView Items { get; }
public CollectionViewSource ItemsViewSource { get; }
public ctor()
{
ObservableCollection<object> items = CreateObservableItems();
this.ItemsViewSource = new CollectionViewSource() {Source = items};
this.Items = this.ItemsViewSource.View;
}
바와 같이에서 제안했다 : 나는 해결책을 찾은 것 같아요 관련 주제에 대한 답변 나는 사용, ListCollectionView
대신 CollectionView
.
어떤 이유로, 작동 ListCollectionView
은하지 않지만 CollectionView
, 후자는 어떤 표시를 제공하지 않는 경우에도, 그것이해야하지 (예를 들어, CollectionView.CanFilter
반환 true
).
나는 누군가가 실제로이 행동에 대한 설명을 제공하는 대답을 제공 할 수 있다면 대신 그러한 대답을 받아들이게되어 기쁩니다.