WPF Combobox Filter 사용법이 궁금합니다.

안녕하세요. Combobox 아이템이 너무 많아 필터기능을 넣고자 하는데 생각만큼 쉽지가 않네요;;

막연하게 바인딩 소스에 필터를 적용해서 갱신을 했더니 초기화가 안되는 문제가 있어서

이것저것 찾아보다 Filter라는 기능과 예제 소스를 찾게 되었는데 계속해서 NotSupporedException 에러

가 뜨면서 작동이 안되네요. 도움부탁드립니다~!

    <DataGridComboBoxColumn x:Name="bizColumn" Header="업 체" Width="0.3*" CellStyle="{StaticResource gridCellStyle}"
        SelectedValueBinding="{Binding ItemInBiz , Mode=TwoWay , UpdateSourceTrigger=PropertyChanged}"
        DisplayMemberPath="Display"
        SelectedValuePath="Value">
        
        <DataGridComboBoxColumn.ElementStyle>
           <Style TargetType="{x:Type ComboBox}">
                <Setter Property="Width" Value="170"/>
                <Setter Property="HorizontalAlignment" Value="Center"/>
                <Setter Property="VerticalAlignment" Value="Center"/>
                <Setter Property="ItemsSource" Value="{Binding FilteredBizList}" />
                <Setter Property="HorizontalContentAlignment" Value="Center"/>
                <Setter Property="VerticalContentAlignment" Value="Center"/>                 
                <Setter Property="ItemContainerStyle" Value="{StaticResource itemcontainer}"/>
                <Setter Property="IsTextSearchEnabled" Value="False"/>
                <EventSetter Event="KeyUp" Handler="Combobox_keyup"/>
       </Style>
 </DataGridComboBoxColumn.ElementStyle>

 <DataGridComboBoxColumn.EditingElementStyle>
     <Style TargetType="{x:Type ComboBox}" >
         <Setter Property="Width" Value="160"/>
          <Setter Property="ItemsSource" Value="{Binding FilteredBizList}" />
         <Setter Property="HorizontalContentAlignment" Value="Center"/>
         <Setter Property="VerticalContentAlignment" Value="Center"/>
         <Setter Property="ItemContainerStyle" Value="{StaticResource itemcontainer}"/>
         <Setter Property="HorizontalAlignment" Value="Center"/>
         <Setter Property="VerticalAlignment" Value="Center"/>
          <Setter Property="IsEditable" Value="True"/>
          <Setter Property="IsTextSearchEnabled" Value="False"/>
         <EventSetter Event="KeyUp" Handler="Combobox_keyup" />
         </Style>
 </DataGridComboBoxColumn.EditingElementStyle>

//Filterd BizList
  BizList = new BindingList<object>();
  BizList.Add(new { Display = "하하", Value = "12345" });
  BizList.Add(new { Display = "호호", Value = "67890" });
  BizList.Add(new { Display = "카캬", Value = "AAAAA" });
  BizList.Add(new { Display = "푸푸", Value = "BBBBB" });
  BizList.Add(new { Display = "소소", Value = "CCCCC" });

//KeyUpEvent Handler
 private void Combobox_keyup(object sender , KeyEventArgs e) 
 {
     ComboBox comboBox = sender as ComboBox;
     comboBox.Items.Filter  -= this.FilterPredicate; //NotSupport 에러
     this.mTextBox = comboBox.Template.FindName("PART_EditableTextBox", comboBox) as TextBox;

    

     if (e.Key == Key.Enter || e.Key == Key.Tab || e.Key == Key.Return)
     {
         return;

     }
     else 
     {
         comboBox.IsDropDownOpen = true;
         comboBox.Items.Filter += this.FilterPredicate; //NotSupport 에러
      }

  
 }

//FilterPredicate
    private bool FilterPredicate(object obj) 
    {
        string sValue = string.Empty;

        if (obj is string)
            sValue = obj.ToString();
        else if (obj is ComboBoxItem)
            sValue = (obj as ComboBoxItem).Content.ToString();
        else 
        {
            System.Reflection.PropertyInfo info = obj.GetType().GetProperty(bizColumn.DisplayMemberPath);
            if (info != null) 
            {
                object oValue = info.GetValue(obj, null);
                if (oValue != null) 
                {
                    sValue = oValue.ToString();
                }
            }
  
        }

        if (!string.IsNullOrEmpty(sValue) && sValue.Contains(this.mTextBox.Text)) return true; else return false;
    
    }

}


2 Likes

제가 틀렸다면 죄송합니다.
Filter를 해서 리스트를 보이는건가요? 아니면 타이핑한 글자를 자동 완성하는 기능인가요?

ComboBox x:Name=“ComboTest” Height=“50” Width=“300” DisplayMemberPath=“Name” IsTextSearchEnabled=“True” TextSearch.TextPath=“Name” IsEditable=“True” IsDropDownOpen=“True” StaysOpenOnEdit=“True”

private ObservableCollection name = new ObservableCollection();

        name.Add(new Person("John", 30));
        name.Add(new Person("Daniel", 31));
        name.Add(new Person("Smith", 32));
        name.Add(new Person("Marry", 25));
        name.Add(new Person("Sarah", 20));

        ComboTest.ItemsSource = name;

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

public int Age { get; set; }

public Person(string name, int age)
{
    Name = name;
    Age = age;
}

}
말씀하신게 이게 맞는지 모르겠습니다. 짧게 만든거라, 만약 틀리다면 알려주세요

2 Likes

안녕하세요. 필터를 해서 리스트가 보이는 겁니다. Text 문자열이 포함된 item이 보이면 됩니다~!

2 Likes

위에 제공해주신 예제로는 동작 되지 않습니다.

혹시나해서
텍스박스 하나, 콤보박스 하나와
위에 주신 비하인드코드 영역부분으로 정상적으로 동작되었습니다!

구성되는 화면이라던가 힌트를 더 주셨으면 하네요!

3 Likes

안녕하세요. 별도의 텍스트박스를 만드는게 아닌 콤보박스의 에디트 기능을 이용하고자 합니다. 예제코드를 참고하여 구현을 했는데 ComboBox의 item의 필터가 적용되지 않고 NotSupport 에러가 발생합니다. (주석참조) 도통 이유를 모르겠네요. 다만 인터넷의 예제와 제 소스 차이점은 Combox item 바인딩 개체가 저는 BindingList이고 인터넷 예제는 List로 되어있습니다. BindingList로 Item을 등록했을 경우에는 Filter를 지원을 안하는건지… 허허;;

3 Likes

아하!
일단 콤보박스의 에디트 기능으로 구현해서 테스트해봤는데
차이점이라고 한다면 DataGrid의 Combox를 사용하지 않았습니다!

한번 비교해서 봐보세요!
XAML

<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:local="clr-namespace:ComboboxFilterTest"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Window.Resources>
        <Style TargetType="{x:Type ComboBox}">
            <Setter Property="Width" Value="170" />
            <Setter Property="Height" Value="21" />
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto" />
            <ColumnDefinition Width="5" />
            <ColumnDefinition Width="auto" />
        </Grid.ColumnDefinitions>
        <ComboBox
            x:Name="bizColumn"
            Grid.Column="2"
            DisplayMemberPath="Display"
            IsEditable="True"
            ItemsSource="{Binding BizList}"
            KeyUp="bizColumn_KeyUp" />
    </Grid>
</Window>

behind

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent ();
        this.DataContext = new MainViewModel ();
    }

    private bool FilterPredicate(object obj)
    {
        string sValue = string.Empty;

        if (obj is string)
            sValue = obj.ToString ();
        else if (obj is ComboBoxItem)
            sValue = (obj as ComboBoxItem).Content.ToString ();
        else
        {
            System.Reflection.PropertyInfo info = obj.GetType ().GetProperty (bizColumn.DisplayMemberPath);
            if (info != null)
            {
                object oValue = info.GetValue (obj, null);
                if (oValue != null)
                {
                    sValue = oValue.ToString ();
                }
            }

        }

        if (!string.IsNullOrEmpty (sValue) && sValue.Contains (tb.Text))
            return true;
        else
            return false;

    }
    TextBox tb;
    private void bizColumn_KeyUp(object sender, KeyEventArgs e)
    {
        ComboBox comboBox = sender as ComboBox;
        comboBox.Items.Filter -= this.FilterPredicate; //NotSupport 에러
        tb = comboBox.Template.FindName ("PART_EditableTextBox", comboBox) as TextBox;



        if (e.Key == Key.Enter || e.Key == Key.Tab || e.Key == Key.Return)
        {
            return;

        }
        else
        {
            comboBox.IsDropDownOpen = true;
            comboBox.Items.Filter += this.FilterPredicate; //NotSupport 에러
        }


    }
}

viewmodel

public class bizModel
{
    public string Display { get; set; }
    public string Value { get; set; }
}
public partial class MainViewModel :ObservableObject
{
    [ObservableProperty] List<bizModel> bizList;
    public MainViewModel()
    {
        BizList = new ();
        BizList.Add (new bizModel { Display = "하하", Value = "12345" });
        BizList.Add (new bizModel { Display = "호호", Value = "67890" });
        BizList.Add (new bizModel { Display = "카캬", Value = "AAAAA" });
        BizList.Add (new bizModel { Display = "푸푸", Value = "BBBBB" });
        BizList.Add (new bizModel { Display = "소소", Value = "CCCCC" });
    }
}

Screenshot 2023-12-19 at 10.46.40

4 Likes

DataGrid의 Combox컬럼이 문제였군요 ㅠㅠ 그리드에 칼럼추가해서 Test해봐야 겠습니다. 예제코드 작동영상까지 너무 너무 감사합니다~!!

2 Likes