programing

WPF를 통한 열거형으로의 ListBox 바인딩(Description Atribute

css3 2023. 4. 15. 09:12

WPF를 통한 열거형으로의 ListBox 바인딩(Description Atribute

ObjectDataProvider 메서드를 사용하여 ListBox를 열거형으로 바인드하여 Description 속성을 표시할 수 있습니까?그렇다면 어떻게 해야 할까?

네, 가능합니다.이거면 될 거야.예를 들어 열거가 있다고 합시다.

public enum MyEnum
{
    [Description("MyEnum1 Description")]
    MyEnum1,
    [Description("MyEnum2 Description")]
    MyEnum2,
    [Description("MyEnum3 Description")]
    MyEnum3
}

그런 다음 ObjectDataProvider를 다음과 같이 사용할 수 있습니다.

xmlns:MyEnumerations="clr-namespace:MyEnumerations"
<ObjectDataProvider MethodName="GetValues"
                ObjectType="{x:Type sys:Enum}"
                x:Key="MyEnumValues">
    <ObjectDataProvider.MethodParameters>
        <x:Type TypeName="MyEnumerations:MyEnum" />
    </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

또한 ListBox에 대해 Items를 설정합니다.MyEnumValues에 소스하여 Converter를 사용하여 ItemTemplate를 적용합니다.

<ListBox Name="c_myListBox" SelectedIndex="0" Margin="8"
        ItemsSource="{Binding Source={StaticResource MyEnumValues}}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

변환기에서 설명을 가져와 반환한다.

public class EnumDescriptionConverter : IValueConverter
{
    private string GetEnumDescription(Enum enumObj)
    {
        FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());

        object[] attribArray = fieldInfo.GetCustomAttributes(false);

        if (attribArray.Length == 0)
        {
            return enumObj.ToString();
        }
        else
        {
            DescriptionAttribute attrib = attribArray[0] as DescriptionAttribute;
            return attrib.Description;
        }
    }

    object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Enum myEnum = (Enum)value;
        string description = GetEnumDescription(myEnum);
        return description;
    }

    object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return string.Empty;
    }
}

GetEnumDescription 메서드는 다른 곳으로 이동해야 하지만 다음과 같은 아이디어가 있습니다.

확장 메서드로 GetEnumDescription을 선택합니다.

다른 솔루션은 열거형에서 항목을 생성하는 커스텀 Markup Extension입니다.이것에 의해, xaml이 보다 컴팩트하고 읽기 쉬워집니다.

using System.ComponentModel;

namespace EnumDemo
{
    public enum Numbers
    {
        [Description("1")]
        One,

        [Description("2")]
        Two,

        Three,
    }
}

사용 예:

<Window x:Class="EnumDemo.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:EnumDemo">

    <ListBox ItemsSource="{local:EnumToCollection EnumType={x:Type local:Numbers}}"/>

</Window>

Markup Extension 구현

using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Markup;

namespace EnumDemo
{
    public class EnumToCollectionExtension : MarkupExtension
    {
        public Type EnumType { get; set; }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (EnumType == null) throw new ArgumentNullException(nameof(EnumType));

            return Enum.GetValues(EnumType).Cast<Enum>().Select(EnumToDescriptionOrString);
        }

        private string EnumToDescriptionOrString(Enum value)
        {
            return value.GetType().GetField(value.ToString())
                       .GetCustomAttributes(typeof(DescriptionAttribute), false)
                       .Cast<DescriptionAttribute>()
                       .FirstOrDefault()?.Description ?? value.ToString();
        }
    }
}

Enum에 바인드할 경우 IValueConverter를 통해 설명으로 변환할 수 있습니다.

콤보 상자를 enum에 바인드...를 참조하십시오. Silverlight!를 참조하십시오.

상세한 것에 대하여는, http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx 를 참조해 주세요.

프로젝트(*.resx 파일)에 resource 파일을 정의할 수 있습니다.이 파일에서는 다음과 같은 "key-value-pairs"를 정의해야 합니다.

"YellowCars" : "Yellow Cars",
"RedCars" : "Red Cars",

기타 등등...

키는 다음과 같이 열거 엔트리와 동일합니다.

public enum CarColors
{
    YellowCars,
    RedCars
}

기타 등등...

WPF 를 사용하는 경우는, 다음과 같이 XAML-Code 에 실장할 수 있습니다.

<ComboBox ItemsSource="{Binding Source={StaticResource CarColors}}" SelectedValue="{Binding CarColor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Converter={StaticResource CarColorConverter}}" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

그런 다음 다음과 같이 Converter를 작성해야 합니다.

using System;
using System.Globalization;
using System.Resources;
using System.Windows.Data;

public class CarColorConverter : IValueConverter
{
    private static ResourceManager CarColors = new ResourceManager(typeof(Properties.CarColors));

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var key = ((Enum)value).ToString();
        var result = CarColors.GetString(key);
        if (result == null) {
            result = key;
        }

        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

내 대답은 7년 늦게 온다;-) 하지만 다른 사람이 쓸 수 있을지도 몰라!

네, 그럴 수도 있어요.

ListBox을 사용하다

다음과 .
ItemsListBox를합니다. 있습니다.리스트 박스

그런 다음 각 ListBoxItem이 생성됩니다.

  • 1단계: Enum을 정의합니다.
public enum EnumValueNames
{ 
   EnumValueName1, 
   EnumValueName2, 
   EnumValueName3
}

그런 다음 선택한 항목을 기록하는 DataContext(또는 MVVM의 ViewModel)에 아래 속성을 추가합니다.

public EnumValueNames SelectedEnumValueName { get; set; }
  • 순서 2: 윈도, 사용자 제어 또는 그리드 등의 정적 리소스에 열거형을 추가합니다.
    <Window.Resources>
        <ObjectDataProvider MethodName="GetValues"
                            ObjectType="{x:Type system:Enum}"
                            x:Key="EnumValueNames">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="local:EnumValueNames" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
  • 순서 3: 목록 상자를 사용하여 각 항목을 채웁니다.
<ListBox ItemsSource="{Binding Source={StaticResource EnumValueNames}}"
              SelectedItem="{Binding SelectedEnumValueName, Mode=TwoWay}" />

참고 자료: https://www.codeproject.com/Articles/130137/Binding-TextBlock-ListBox-RadioButtons-to-Enums

이 예는 ComboBox에 적용되지만 모든 Enum Binding에서 동일하게 작동합니다.

출처:

이 anwser는 Brian Lagunas의 EnumBindingSourceExtension + EnumDescription의 원본 작업을 기반으로 합니다.타입 컨버터나는 내 필요에 맞게 그것을 수정했다.

변경 내용:

  1. EnumValue에 [Description] 속성이 있는지 확인하는 부울 함수로 Enum 클래스를 확장했습니다.

    public static bool HasDescriptionAttribute(this Enum value)
    {
        var attribute = value.GetType().GetField(value.ToString())
                            .GetCustomAttributes(typeof(DescriptionAttribute), false)
                            .FirstOrDefault();                                
    
        return (attribute != null);
    }
    
  2. EnumDescription에서 Brian의 ConvertTo() 함수를 수정했습니다.[Description] 속성이 적용되지 않은 경우 "null"을 반환하는 TypeConverter

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        ...
        // Original: return ((attributes.Length > 0) && (!String.IsNullOrEmpty(attributes[0].Description))) ? attributes[0].Description : value.ToString();
        return ((attributes.Length > 0) && (!String.IsNullOrEmpty(attributes[0].Description))) ? attributes[0].Description : null;
    }
    
  3. 자신의 함수를 호출하여 반환값을 편집하여 "EnumBindingSourceExtension"에서 Brian의 "ProvideValue()" 함수를 수정했습니다.

    ProvideValue(IServiceProvider serviceProvider)
    {
        ...
        // Original: return enumValues
        return SortEnumValuesByIndex(enumValues);
    
        ...
        // Original: return tempArray
        return SortEnumValuesByIndex(tempArray);
    }
    

    또한 인덱스로 열거형 정렬(프로젝트를 통과할 때 원래 코드에 문제가 있음) 및 [Description] 속성이 없는 값 제거에 기능을 추가합니다.

    private object SortEnumValuesByIndex(Array enumValues)
    {
        var values = enumValues.Cast<Enum>().ToList();
        var indexed = new Dictionary<int, Enum>();
        foreach (var value in values)
        {
            int index = (int)Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()));
            indexed.Add(index, value);
        }
    
        return indexed.OrderBy(x => x.Key).Select(x => x.Value).Where(x => x.HasDescriptionAttribute()).Cast<Enum>();
    }     
    

다음 예는 ComboBoxes에 적용되어 있습니다.

주의: 이미지를 서버에 업로드할 때 오류가 발생하여 해당 이미지에 URL을 추가했습니다.

<ComboBox x:Name="ConversionPreset_ComboBox" Grid.Row="4" Grid.Column="1" Margin="5,5,5,5" ItemsSource="{objects:EnumBindingSource EnumType={x:Type enums:ConversionPreset}}" SelectedIndex="2" SelectionChanged="ConversionPreset_ComboBox_SelectionChanged" />
<ComboBox x:Name="OutputType_ComboBox" Grid.Row="4" Grid.Column="2" Margin="5,5,5,5" ItemsSource="{objects:EnumBindingSource EnumType={x:Type enums:Output}}" SelectedIndex="1" SelectionChanged="OutputType_ComboBox_SelectionChanged" />

뒤에 코드 있음:

    private Enumeration.Output Output { get; set; }

    private void OutputType_ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        => Output = (Enumeration.Output)OutputType_ComboBox.SelectedItem;

    private Enumeration.ConversionPreset ConversionPreset { get; set; }

    private void ConversionPreset_ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        => ConversionPreset = (Enumeration.ConversionPreset)ConversionPreset_ComboBox.SelectedItem;

"ConversionPreset" 열거 및 렌더링된 ComboBox 그림

[TypeConverter(typeof(EnumDescriptionTypeConverter))]
public enum ConversionPreset
{
    [Description("Very Slow (Smaller File Size)")]
    VerySlow = -2,

    [Description("Slow (Smaller File Size)")]
    Slow = -1,

    [Description("Medium (Balanced File Size)")]
    Medium = 0,

    [Description("Fast (Bigger File Size)")]
    Fast = 1,

    [Description("Very Fast (Bigger File Size)")]
    VeryFast = 2,

    [Description("Ultra Fast (Biggest File Size)")]
    UltraFast = 3
}

렌더링된 ComboBox의 "출력" 열거 및 그림

[TypeConverter(typeof(EnumDescriptionTypeConverter))]
public enum Output
{
    // This will be hidden in the Output
    None = -1,

    [Description("Video")]
    Video = 0,

    [Description("Audio")]
    Audio = 1
}

언급URL : https://stackoverflow.com/questions/3985876/wpf-binding-a-listbox-to-an-enum-displaying-the-description-attribute