(WPF) Enum타입 바인딩 필터 처리

 

Enum 상수 값 들을 콤보박스나 라디오 버튼 리스트의 아이템으로 바인딩 해야 하는 경우 System.Windows.Markup.MarkupExtension 를 활용해서 바인딩 처리 할 수 있습니다.
그리고 Enum 상수 값을 필터 처리 해서 원하는 요소만 보이게 처리하는 방법에 대해 알아보겠습니다.

Enum 상수 바인딩

다음과 같은 Enum이 있습니다.

public enum ETest
{
  A,
  B,
  C,
  D,
  E
}

위 ETest 상수들을 콤보박스 아이템으로 바인딩 하면서 원하는 값 만 표시되도록 처리 하고자 합니다.
각 뷰 모델에서 ETest의 값 열거 타입 속성을 만들어서 컨버터를 사용해서 처리 해도 좋지만, 특정 Enum타입이 아닌
모든 Enum에서 사용 가능하도록 처리 하는 것이 더 좋을 것 같습니다.

이를 위해서 공통으로 사용할 수 있는 System.Windows.Markup.MarkupExtension 을 다음과 같이 만들어 사용할 수 있습니다.

public class EnumBindingSourceExtension : MarkupExtension
{
  private Type _enumType;
  
  /// <summary>
  /// 기본 생성자
  /// </summary>
  public EnumBindingSourceExtension() { }
  
  /// <summary>
  /// enum 타입 파라메터 생성자
  /// </summary>
  /// <param name="enumType"></param>
  public EnumBindingSourceExtension(Type enumType)
  {
    this.EnumType = enumType;
  }
                
  public Type EnumType
  {
    get { return this._enumType; }
    private set
    {
      if (value != this._enumType)
      {
        if (null != value)
        {
          // null 타입 체크
          Type enumType = Nullable.GetUnderlyingType(value) ?? value;
          if (!enumType.IsEnum)
            throw new ArgumentException("Enum 타입이 아닙니다!");
         }
        
          this._enumType = value;
        }
      }
    }
  
  public string Fillter
  {
    get; set;
  }
  
  public override object ProvideValue(IServiceProvider serviceProvider)
  {
    if (null == this._enumType)
      throw new InvalidOperationException("Enum 타입이 아닙니다!");
    
    Type enumType = Nullable.GetUnderlyingType(this._enumType) ?? this._enumType;
    Array enumValues = Enum.GetValues(enumType);
    
    if (enumType == this._enumType)
    {
      if (string.IsNullOrWhiteSpace(Fillter))
      {
        return enumValues;
      }
      else
      {
        var fillterArr = Fillter.ToString().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
        return enumValues.Cast<Enum>().Where(p => fillterArr.Contains(p.ToString()));
      }
    }
    
    {
      Array enumValArr = Array.CreateInstance(enumType, enumValues.Length + 1);
      enumValues.CopyTo(enumValArr, 1);
      
      if (string.IsNullOrWhiteSpace(Fillter))
      {
        return enumValues;
      }
      else
      {
        var fillterArr = Fillter.ToString().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
        return enumValues.Cast<Enum>().Where(p => fillterArr.Contains(p.ToString()));
      }
    }
  }
}

간단히 코드를 보면 생성자를 통해 EnumType 속성에 바인딩 대상의 Enum 타입을 설정하고, 표시 할 상수 값을 지정할 수 있도록 Fillter 속성이 있습니다.
Fillter 속성은 콤마(,)로 구분 짓고 있으며 ProvideValue() 메서드의 코드를 간단히 살펴보면 System.Enum 의 GetValues() 메서드를 통해 Enum 상수 배열을 뽑아 냅니다.
그리고 Fillter 속성을 체크해서 원하는 상수 값만 다시 한번 뽑아 반환 시켜 줍니다.

EnumBindingSourceExtension 사용

xaml에서 다음과 같이 위에서 만든 EnumBindingSourceExtension을 사용할 수 있습니다.

[ViewModel.cs]

private ETest _selectedETest = ETest.A;

public ETest SelectedETest
{
  get => _selectedETest;
  set
  {
    _selectedETest = value;
    OnPropertyChanged();
  }
}

뷰 xaml에서 EnumBindingSourceExtension 네임스페이스를 추가해 주고

[View.xaml]

<ComboBox ItemsSource="{Binding Source={local:EnumBindingSource {x:Type local:ETest}, Fillter='A,C'}}"
          SelectedItem="{Binding SelectedETest}"/>

위 처럼 Enum ETest을 콤보박스 아이템으로 바인딩 처리 동시에 상수 값 A, C 만 콤보박스 아이템으로 표시 되는 걸 확인할 수 있습니다.
동시에 콤보박스 아이템 선택시 해당 Enum 값에 맞게 SelectedETest에 정상 바인딩 되는 것을 확인할 수 있습니다.