it-swarm.com.de

Wie binde ich eine Enumeration an ein Combobox-Steuerelement in WPF?

Ich versuche, ein einfaches Beispiel zu finden, in dem die Aufzählungen so angezeigt werden, wie sie sind. Alle Beispiele, die ich gesehen habe, versuchen, gut aussehende Anzeigezeichenfolgen hinzuzufügen, aber ich möchte diese Komplexität nicht.

Grundsätzlich habe ich eine Klasse, die alle Eigenschaften enthält, die ich binde, indem ich zuerst den DataContext auf diese Klasse setze und dann die Bindung wie folgt in der xaml-Datei spezifiziere:

<ComboBox ItemsSource="{Binding Path=EffectStyle}"/>

Dies zeigt jedoch nicht die Aufzählungswerte in ComboBox als Elemente an.

166
Joan Venge

Sie können dies aus dem Code heraus tun, indem Sie beispielsweise den folgenden Code in die Ereignisbehandlungsroutine von Window Loaded einfügen:

yourComboBox.ItemsSource = Enum.GetValues(typeof(EffectStyle)).Cast<EffectStyle>();

Wenn Sie es in XAML binden müssen, müssen Sie ObjectDataProvider verwenden, um ein Objekt zu erstellen, das als Bindungsquelle verfügbar ist:

<Window x:Class="YourNamespace.MainWindow"
        xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
        xmlns:System="clr-namespace:System;Assembly=mscorlib"
        xmlns:StyleAlias="clr-namespace:Motion.VideoEffects">
    <Window.Resources>
        <ObjectDataProvider x:Key="dataFromEnum" MethodName="GetValues"
                            ObjectType="{x:Type System:Enum}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="StyleAlias:EffectStyle"/>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
    <Grid>
        <ComboBox ItemsSource="{Binding Source={StaticResource dataFromEnum}}"
                  SelectedItem="{Binding Path=CurrentEffectStyle}" />
    </Grid>
</Window>

Machen Sie auf den nächsten Code aufmerksam:

xmlns:System="clr-namespace:System;Assembly=mscorlib"
xmlns:StyleAlias="clr-namespace:Motion.VideoEffects"

Anleitungen zum Zuordnen von Namespace und Assembly finden Sie unter MSDN .

279
Kyrylo M

Ich mag es, wenn alle Objekte, die ich binde, in meinem ViewModel definiert sind, also versuche ich, <ObjectDataProvider> In der XAML zu vermeiden, wenn dies möglich ist.

Meine Lösung verwendet keine in der Ansicht definierten Daten und keinen Code-Behind. Nur eine DataBinding, ein wiederverwendbarer ValueConverter, eine Methode zum Abrufen einer Auflistung von Beschreibungen für einen beliebigen Enum-Typ und eine einzelne Eigenschaft im ViewModel, an die gebunden werden soll.

Wenn ich ein Enum an ein ComboBox binden möchte, stimmt der anzuzeigende Text nie mit den Werten des Enum überein, daher verwende ich die [Description()] Attribut, um ihm den Text zu geben, den ich eigentlich im ComboBox sehen möchte. Wenn ich in einem Spiel eine Anzahl von Charakterklassen hätte, würde das ungefähr so ​​aussehen:

public enum PlayerClass
{
  // add an optional blank value for default/no selection
  [Description("")]
  NOT_SET = 0,
  [Description("Shadow Knight")]
  SHADOW_KNIGHT,
  ...
}

Zuerst habe ich eine Hilfsklasse mit einigen Methoden erstellt, um mit Aufzählungen umzugehen. Eine Methode ruft eine Beschreibung für einen bestimmten Wert ab, die andere Methode ruft alle Werte und ihre Beschreibungen für einen Typ ab.

public static class EnumHelper
{
  public static string Description(this Enum value)
  {
    var attributes = value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
    if (attributes.Any())
      return (attributes.First() as DescriptionAttribute).Description;

    // If no description is found, the least we can do is replace underscores with spaces
    // You can add your own custom default formatting logic here
    TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
    return ti.ToTitleCase(ti.ToLower(value.ToString().Replace("_", " ")));
  }

  public static IEnumerable<ValueDescription> GetAllValuesAndDescriptions(Type t)
  {
    if (!t.IsEnum)
      throw new ArgumentException($"{nameof(t)} must be an enum type");

    return Enum.GetValues(t).Cast<Enum>().Select((e) => new ValueDescription() { Value = e, Description = e.Description() }).ToList();
  }
}

Als nächstes erstellen wir ein ValueConverter. Das Erben von MarkupExtension erleichtert die Verwendung in XAML, sodass wir es nicht als Ressource deklarieren müssen.

[ValueConversion(typeof(Enum), typeof(IEnumerable<ValueDescription>))]
public class EnumToCollectionConverter : MarkupExtension, IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
    return EnumHelper.GetAllValuesAndDescriptions(value.GetType());
  }
  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
    return null;
  }
  public override object ProvideValue(IServiceProvider serviceProvider)
  {
    return this;
  }
}

Mein ViewModel benötigt nur 1 Eigenschaft, an die mein View sowohl für das SelectedValue als auch für das ItemsSource der Combobox binden kann:

private PlayerClass playerClass;

public PlayerClass SelectedClass
{
  get { return playerClass; }
  set
  {
    if (playerClass != value)
    {
      playerClass = value;
      OnPropertyChanged(nameof(SelectedClass));
    }
  }
}

Und zum Schluss binden Sie die ComboBox -Ansicht (mit der ValueConverter in der ItemsSource -Bindung) ...

<ComboBox ItemsSource="{Binding Path=SelectedClass, Converter={x:EnumToCollectionConverter}, Mode=OneTime}"
          SelectedValuePath="Value"
          DisplayMemberPath="Description"
          SelectedValue="{Binding Path=SelectedClass}" />

Um diese Lösung zu implementieren, müssen Sie nur meine Klassen EnumHelper und EnumToCollectionConverter kopieren. Sie werden mit any Enums arbeiten. Außerdem habe ich es hier nicht aufgenommen, aber die Klasse ValueDescription ist nur eine einfache Klasse mit zwei öffentlichen Objekteigenschaften, eine mit dem Namen Value, eine mit dem Namen Description. Sie können das selbst erstellen oder den Code ändern, um einen Tuple<object, object> Oder KeyValuePair<object, object> Zu verwenden.

102
Nick

Ich habe eine andere Lösung mit MarkupExtension verwendet.

  1. Ich habe eine Klasse erstellt, die die Quelle der Gegenstände enthält:

    public class EnumToItemsSource : MarkupExtension
    {
        private readonly Type _type;
    
        public EnumToItemsSource(Type type)
        {
            _type = type;
        }
    
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return Enum.GetValues(_type)
                .Cast<object>()
                .Select(e => new { Value = (int)e, DisplayName = e.ToString() });
        }
    }
    
  2. Das ist fast alles ... Jetzt in XAML verwenden:

        <ComboBox DisplayMemberPath="DisplayName"
              ItemsSource="{persons:EnumToItemsSource {x:Type enums:States}}"
              SelectedValue="{Binding Path=WhereEverYouWant}"
              SelectedValuePath="Value" />
    
  3. Ändern Sie "Enums: States" in Ihre Enumeration

45
tom.maruska

Verwenden Sie ObjectDataProvider:

<ObjectDataProvider x:Key="enumValues"
   MethodName="GetValues" ObjectType="{x:Type System:Enum}">
      <ObjectDataProvider.MethodParameters>
           <x:Type TypeName="local:ExampleEnum"/>
      </ObjectDataProvider.MethodParameters>
 </ObjectDataProvider>

und binden Sie dann an statische Ressource:

ItemsSource="{Binding Source={StaticResource enumValues}}"

basierend auf dieser Artikel

21
druss

Nicks Antwort hat mir sehr geholfen, aber ich erkannte, dass es leicht angepasst werden könnte, um eine zusätzliche Klasse, ValueDescription, zu vermeiden. Ich erinnerte mich, dass es bereits eine KeyValuePair-Klasse im Framework gibt, sodass diese stattdessen verwendet werden kann.

Der Code ändert sich nur geringfügig:

public static IEnumerable<KeyValuePair<string, string>> GetAllValuesAndDescriptions<TEnum>() where TEnum : struct, IConvertible, IComparable, IFormattable
    {
        if (!typeof(TEnum).IsEnum)
        {
            throw new ArgumentException("TEnum must be an Enumeration type");
        }

        return from e in Enum.GetValues(typeof(TEnum)).Cast<Enum>()
               select new KeyValuePair<string, string>(e.ToString(),  e.Description());
    }


public IEnumerable<KeyValuePair<string, string>> PlayerClassList
{
   get
   {
       return EnumHelper.GetAllValuesAndDescriptions<PlayerClass>();
   }
}

und schließlich die XAML:

<ComboBox ItemSource="{Binding Path=PlayerClassList}"
          DisplayMemberPath="Value"
          SelectedValuePath="Key"
          SelectedValue="{Binding Path=SelectedClass}" />

Ich hoffe das ist hilfreich für andere.

9
Roger

Sie müssen ein Array der Werte in der Aufzählung erstellen, das durch Aufrufen von System.Enum.GetValues ​​() erstellt werden kann, wobei das Type der Aufzählung übergeben wird, die Sie erstellt haben wollen die Artikel von.

Wenn Sie dies für die Eigenschaft ItemsSource angeben, sollten alle Werte der Aufzählung darin enthalten sein. Sie möchten wahrscheinlich SelectedItem an EffectStyle binden (vorausgesetzt, es ist eine Eigenschaft derselben Aufzählung und enthält den aktuellen Wert).

8
Andy

Alle oben genannten Beiträge haben einen einfachen Trick übersehen. Anhand der Bindung von SelectedValue können Sie herausfinden, wie Sie die ItemsSource AUTOMAGICALLY füllen, damit Ihr XAML-Markup korrekt ist.

<Controls:EnumComboBox SelectedValue="{Binding Fool}"/>

Zum Beispiel in meinem ViewModel habe ich

public enum FoolEnum
    {
        AAA, BBB, CCC, DDD

    };


    FoolEnum _Fool;
    public FoolEnum Fool
    {
        get { return _Fool; }
        set { ValidateRaiseAndSetIfChanged(ref _Fool, value); }
    }

ValidateRaiseAndSetIfChanged ist mein INPC-Hook. Ihre können abweichen.

Die Implementierung von EnumComboBox sieht folgendermaßen aus, aber zuerst benötige ich einen kleinen Helfer, um meine Aufzählungszeichenfolgen und -werte abzurufen

    public static List<Tuple<object, string, int>> EnumToList(Type t)
    {
        return Enum
            .GetValues(t)
            .Cast<object>()
            .Select(x=>Tuple.Create(x, x.ToString(), (int)x))
            .ToList();
    }

und die Hauptklasse (Hinweis: Ich verwende ReactiveUI zum Verknüpfen von Eigenschaftsänderungen über WhenAny.)

using ReactiveUI;
using ReactiveUI.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Documents;

namespace My.Controls
{
    public class EnumComboBox : System.Windows.Controls.ComboBox
    {
        static EnumComboBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(EnumComboBox), new FrameworkPropertyMetadata(typeof(EnumComboBox)));
        }

        protected override void OnInitialized( EventArgs e )
        {
            base.OnInitialized(e);

            this.WhenAnyValue(p => p.SelectedValue)
                .Where(p => p != null)
                .Select(o => o.GetType())
                .Where(t => t.IsEnum)
                .DistinctUntilChanged()
                .ObserveOn(RxApp.MainThreadScheduler)
                .Subscribe(FillItems);
        }

        private void FillItems(Type enumType)
        {
            List<KeyValuePair<object, string>> values = new List<KeyValuePair<object,string>>();

            foreach (var idx in EnumUtils.EnumToList(enumType))
            {
                values.Add(new KeyValuePair<object, string>(idx.Item1, idx.Item2));
            }

            this.ItemsSource = values.Select(o=>o.Key.ToString()).ToList();

            UpdateLayout();
            this.ItemsSource = values;
            this.DisplayMemberPath = "Value";
            this.SelectedValuePath = "Key";

        }
    }
}

Sie müssen den Stil auch in Generic.XAML korrekt einstellen, da Ihre Box sonst nichts rendert und Sie sich die Haare ausreißen.

<Style TargetType="{x:Type local:EnumComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}">
</Style>

und das ist das. Dies könnte natürlich erweitert werden, um i18n zu unterstützen, würde aber den Beitrag verlängern.

4
bradgonesurfing

Es gibt viele ausgezeichnete Antworten auf diese Frage und ich reiche meine demütig ein. Ich finde, dass meine etwas einfacher und eleganter ist. Es wird nur ein Wertekonverter benötigt.

Angesichts einer Aufzählung ...

public enum ImageFormat
{
    [Description("Windows Bitmap")]
    BMP,
    [Description("Graphics Interchange Format")]
    GIF,
    [Description("Joint Photographic Experts Group Format")]
    JPG,
    [Description("Portable Network Graphics Format")]
    PNG,
    [Description("Tagged Image Format")]
    TIFF,
    [Description("Windows Media Photo Format")]
    WDP
}

und ein Wertekonverter ...

public class ImageFormatValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is ImageFormat format)
        {
            return GetString(format);
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is string s)
        {
            return Enum.Parse(typeof(ImageFormat), s.Substring(0, s.IndexOf(':')));
        }
        return null;
    }

    public string[] Strings => GetStrings();

    public static string GetString(ImageFormat format)
    {
        return format.ToString() + ": " + GetDescription(format);
    }

    public static string GetDescription(ImageFormat format)
    {
        return format.GetType().GetMember(format.ToString())[0].GetCustomAttribute<DescriptionAttribute>().Description;

    }
    public static string[] GetStrings()
    {
        List<string> list = new List<string>();
        foreach (ImageFormat format in Enum.GetValues(typeof(ImageFormat)))
        {
            list.Add(GetString(format));
        }

        return list.ToArray();
    }
}

ressourcen...

    <local:ImageFormatValueConverter x:Key="ImageFormatValueConverter"/>

XAML-Deklaration ...

    <ComboBox Grid.Row="9" ItemsSource="{Binding Source={StaticResource ImageFormatValueConverter}, Path=Strings}"
              SelectedItem="{Binding Format, Converter={StaticResource ImageFormatValueConverter}}"/>

Modell anzeigen ...

    private ImageFormat _imageFormat = ImageFormat.JPG;
    public ImageFormat Format
    {
        get => _imageFormat;
        set
        {
            if (_imageFormat != value)
            {
                _imageFormat = value;
                OnPropertyChanged();
            }
        }
    }

Resultierende Combobox ...

ComboBox bound to enum

2
AQuirky
public class EnumItemsConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!value.GetType().IsEnum)
            return false;

        var enumName = value.GetType();
        var obj = Enum.Parse(enumName, value.ToString());

        return System.Convert.ToInt32(obj);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Enum.ToObject(targetType, System.Convert.ToInt32(value));
    }
}

Sie sollten Rogers und Gregs Antwort mit einer solchen Art von Enum-Wertkonverter erweitern, wenn Sie direkt an die Eigenschaften des Enum-Objektmodells binden.

2
Ruberoid

Universelle Apps scheinen etwas anders zu funktionieren. Es verfügt nicht über die volle Leistungsfähigkeit von XAML. Was bei mir funktioniert hat ist:

  1. Ich habe eine Liste der Aufzählungswerte als Aufzählungen erstellt (nicht in Zeichenfolgen oder Ganzzahlen konvertiert) und die ComboBox ItemsSource daran gebunden
  2. Dann könnte ich die ComboBox ItemSelected an meine öffentliche Eigenschaft binden, deren Typ die fragliche Aufzählung ist

Nur zum Spaß habe ich eine kleine Klasse mit Vorlagen zusammengestellt, um dies zu unterstützen, und sie auf den MSDN-Beispielseiten veröffentlicht. Mit den zusätzlichen Bits kann ich optional die Namen der Aufzählungen überschreiben und einige der Aufzählungen ausblenden. Mein Code sieht schrecklich aus wie der von Nick (oben), den ich gerne früher gesehen hätte.

Running the sample; it includes multiple twoway bindings to the enum

2
PESMITH_MSFT

Wenn Sie an eine tatsächliche enum -Eigenschaft in Ihrem ViewModel binden, nicht an eine int-Darstellung einer enum, wird es schwierig. Ich habe festgestellt, dass es notwendig ist, an die Zeichenfolgendarstellung zu binden, NICHT an den int-Wert, wie in allen obigen Beispielen erwartet.

Ob dies der Fall ist, können Sie feststellen, indem Sie ein einfaches Textfeld an die Eigenschaft binden, an die Sie in Ihrem ViewModel binden möchten. Wenn Text angezeigt wird, binden Sie an die Zeichenfolge. Wenn eine Zahl angezeigt wird, binden Sie an den Wert. Hinweis Ich habe Display zweimal verwendet, was normalerweise ein Fehler ist, aber nur so funktioniert es.

<ComboBox SelectedValue="{Binding ElementMap.EdiDataType, Mode=TwoWay}"
                      DisplayMemberPath="Display"
                      SelectedValuePath="Display"
                      ItemsSource="{Binding Source={core:EnumToItemsSource {x:Type edi:EdiDataType}}}" />

Greg

1
Greg Gum

Einfache und klare Erklärung: http://brianlagunas.com/a-better-way-to-data-bind-enums-in-wpf/

xmlns:local="clr-namespace:BindingEnums"
xmlns:sys="clr-namespace:System;Assembly=mscorlib"

...

<Window.Resources>
    <ObjectDataProvider x:Key="dataFromEnum" MethodName="GetValues"
                        ObjectType="{x:Type sys:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="local:Status"/>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

...

<Grid>
    <ComboBox HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="150"
              ItemsSource="{Binding Source={StaticResource dataFromEnum}}"/>
</Grid>
1
jlo-gmail

Ich mochte tom.maruskas Antwort , aber ich musste jeden Aufzählungstyp unterstützen, den meine Vorlage zur Laufzeit antreffen könnte. Dafür musste ich eine Bindung verwenden, um den Typ für die Markup-Erweiterung anzugeben. Ich konnte in diese Antwort von nicolay.anykienko arbeiten, um eine sehr flexible Markup-Erweiterung zu entwickeln, die auf jeden Fall funktioniert, an die ich denken kann. Es wird wie folgt konsumiert:

<ComboBox SelectedValue="{Binding MyEnumProperty}" 
          SelectedValuePath="Value"
          ItemsSource="{local:EnumToObjectArray SourceEnum={Binding MyEnumProperty}}" 
          DisplayMemberPath="DisplayName" />

Die Quelle für die oben genannte Mashed-Up-Markup-Erweiterung:

class EnumToObjectArray : MarkupExtension
{
    public BindingBase SourceEnum { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
        DependencyObject targetObject;
        DependencyProperty targetProperty;

        if (target != null && target.TargetObject is DependencyObject && target.TargetProperty is DependencyProperty)
        {
            targetObject = (DependencyObject)target.TargetObject;
            targetProperty = (DependencyProperty)target.TargetProperty;
        }
        else
        {
            return this;
        }

        BindingOperations.SetBinding(targetObject, EnumToObjectArray.SourceEnumBindingSinkProperty, SourceEnum);

        var type = targetObject.GetValue(SourceEnumBindingSinkProperty).GetType();

        if (type.BaseType != typeof(System.Enum)) return this;

        return Enum.GetValues(type)
            .Cast<Enum>()
            .Select(e => new { Value=e, Name = e.ToString(), DisplayName = Description(e) });
    }

    private static DependencyProperty SourceEnumBindingSinkProperty = DependencyProperty.RegisterAttached("SourceEnumBindingSink", typeof(Enum)
                       , typeof(EnumToObjectArray), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));

    /// <summary>
    /// Extension method which returns the string specified in the Description attribute, if any.  Oherwise, name is returned.
    /// </summary>
    /// <param name="value">The enum value.</param>
    /// <returns></returns>
    public static string Description(Enum value)
    {
        var attrs = value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
        if (attrs.Any())
            return (attrs.First() as DescriptionAttribute).Description;

        //Fallback
        return value.ToString().Replace("_", " ");
    }
}
1
Hamish

Ich füge meinen Kommentar hinzu (in VB, leider, aber das Konzept kann leicht auf C # übertragen werden), weil ich nur darauf verweisen musste und keine der Antworten mochte, da sie zu komplex waren. Es sollte nicht so schwierig sein müssen.

Also habe ich einen einfacheren Weg gefunden. Binden Sie die Enumeratoren an ein Dictionary. Binden Sie das Wörterbuch an die Combobox.

Meine Combobox:

<ComboBox x:Name="cmbRole" VerticalAlignment="Stretch" IsEditable="False" Padding="2" 
    Margin="0" FontSize="11" HorizontalAlignment="Stretch" TabIndex="104" 
    SelectedValuePath="Key" DisplayMemberPath="Value" />

Mein Code-Behind. Hoffentlich hilft das jemand anderem.

Dim tDict As New Dictionary(Of Integer, String)
Dim types = [Enum].GetValues(GetType(Helper.Enumerators.AllowedType))
For Each x As Helper.Enumerators.AllowedType In types
    Dim z = x.ToString()
    Dim y = CInt(x)
    tDict.Add(y, z)
Next

cmbRole.ClearValue(ItemsControl.ItemsSourceProperty)
cmbRole.ItemsSource = tDict
0
Laki Politis

Die Lösung von Nick lässt sich noch weiter vereinfachen. Sie benötigen nur einen einzigen Konverter:

[ValueConversion(typeof(Enum), typeof(IEnumerable<Enum>))]
public class EnumToCollectionConverter : MarkupExtension, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var r = Enum.GetValues(value.GetType());
        return r;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}

Dann verwenden Sie diese Option, wo immer Sie möchten, dass Ihr Kombinationsfeld angezeigt wird:

<ComboBox ItemsSource="{Binding PagePosition, Converter={converter:EnumToCollectionConverter}, Mode=OneTime}"  SelectedItem="{Binding PagePosition}" />
0
Jack

Mit ReactiveUI habe ich die folgende alternative Lösung erstellt. Es ist keine elegante Komplettlösung, aber ich denke zumindest, dass sie lesbar ist.

In meinem Fall ist das Binden einer Liste von enum an ein Steuerelement ein seltener Fall, sodass ich die Lösung nicht über die Codebasis skalieren muss. Der Code kann jedoch allgemeiner gestaltet werden, indem EffectStyleLookup.Item In ein Object geändert wird. Ich habe es mit meinem Code getestet, es sind keine weiteren Modifikationen notwendig. Dies bedeutet, dass die eine Hilfsklasse auf jede enum -Liste angewendet werden kann. Dies würde jedoch die Lesbarkeit beeinträchtigen - ReactiveList<EnumLookupHelper> Klingt nicht besonders gut.

Verwenden der folgenden Hilfsklasse:

public class EffectStyleLookup
{
    public EffectStyle Item { get; set; }
    public string Display { get; set; }
}

Konvertieren Sie im ViewModel die Liste der Aufzählungen und machen Sie sie als Eigenschaft verfügbar:

public ViewModel : ReactiveObject
{
  private ReactiveList<EffectStyleLookup> _effectStyles;
  public ReactiveList<EffectStyleLookup> EffectStyles
  {
    get { return _effectStyles; }
    set { this.RaiseAndSetIfChanged(ref _effectStyles, value); }
  }

  // See below for more on this
  private EffectStyle _selectedEffectStyle;
  public EffectStyle SelectedEffectStyle
  {
    get { return _selectedEffectStyle; }
    set { this.RaiseAndSetIfChanged(ref _selectedEffectStyle, value); }
  }

  public ViewModel() 
  {
    // Convert a list of enums into a ReactiveList
    var list = (IList<EffectStyle>)Enum.GetValues(typeof(EffectStyle))
      .Select( x => new EffectStyleLookup() { 
        Item = x, 
        Display = x.ToString()
      });

    EffectStyles = new ReactiveList<EffectStyle>( list );
  }
}

Verwenden Sie in der ComboBox die SelectedValuePath -Eigenschaft, um an den ursprünglichen enum -Wert zu binden:

<ComboBox Name="EffectStyle" DisplayMemberPath="Display" SelectedValuePath="Item" />

In der Ansicht können wir damit das ursprüngliche enum an das SelectedEffectStyle im ViewModel binden, aber den ToString() -Wert im ComboBox anzeigen:

this.WhenActivated( d =>
{
  d( this.OneWayBind(ViewModel, vm => vm.EffectStyles, v => v.EffectStyle.ItemsSource) );
  d( this.Bind(ViewModel, vm => vm.SelectedEffectStyle, v => v.EffectStyle.SelectedValue) );
});
0
Mitkins