473 Stimmen

Wie bindet man RadioButtons an eine Aufzählung?

Ich habe eine Aufzählung wie diese:

public enum MyLovelyEnum
{
    FirstSelection,
    TheOtherSelection,
    YetAnotherOne
};

Ich habe eine Eigenschaft in meinem DataContext:

public MyLovelyEnum VeryLovelyEnum { get; set; }

Und ich habe drei RadioButtons in meinem WPF-Client.

<RadioButton Margin="3">First Selection</RadioButton>
<RadioButton Margin="3">The Other Selection</RadioButton>
<RadioButton Margin="3">Yet Another one</RadioButton>

Wie binde ich nun die RadioButtons an die Eigenschaft für eine ordnungsgemäße Zwei-Wege-Bindung?

4 Stimmen

Wenn Sie dies tun möchten, ohne einzelne RadioButtons in Ihrer XAML zu spezifizieren, würde ich eine ListBox empfehlen, die an die Enum-Werte gebunden ist, wie diese o diese und die Elementvorlage überschrieben, um RadioButtons zu verwenden, wie diese .

630voto

Scott Punkte 11560

Sie können die akzeptierte Antwort weiter vereinfachen. Anstatt die Enums als Strings in Xaml abzutippen und mehr Arbeit in Ihrem Konverter zu machen als nötig, können Sie explizit den Enum-Wert anstelle einer String-Darstellung übergeben, und wie CrimsonX kommentierte, werden Fehler zur Kompilierzeit und nicht zur Laufzeit ausgelöst:

ConverterParameter={x:Static local:YourEnumType.Enum1}

<StackPanel>
    <StackPanel.Resources>          
        <local:ComparisonConverter x:Key="ComparisonConverter" />          
    </StackPanel.Resources>
    <RadioButton IsChecked="{Binding Path=YourEnumProperty, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static local:YourEnumType.Enum1}}" />
    <RadioButton IsChecked="{Binding Path=YourEnumProperty, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static local:YourEnumType.Enum2}}" />
</StackPanel>

Vereinfachen Sie dann den Konverter:

public class ComparisonConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value?.Equals(parameter);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value?.Equals(true) == true ? parameter : Binding.DoNothing;
    }
}

Bearbeiten (16. Dezember '10):

Dank an anon für Vorschlag: Binding.DoNothing anstelle von DependencyProperty.UnsetValue zurückgeben.


Hinweis - Mehrere Gruppen von RadioButtons im gleichen Container (17. Februar '11):

In xaml, wenn Optionsschaltflächen teilen sich die gleichen übergeordneten Container, dann wählen Sie eine deaktivieren Sie alle anderen innerhalb dieses Containers (auch wenn sie an eine andere Eigenschaft gebunden sind). Versuchen Sie also, Ihre RadioButtons, die an eine gemeinsame Eigenschaft gebunden sind, in einem eigenen Container wie einem Stapel-Panel zu gruppieren. In Fällen, in denen Ihre verwandten RadioButtons nicht in einem einzigen übergeordneten Container untergebracht werden können, setzen Sie die GroupName-Eigenschaft der einzelnen RadioButtons auf einen gemeinsamen Wert, um sie logisch zu gruppieren.

Bearbeiten (5. April '11):

Das if-else von ConvertBack wurde vereinfacht, um einen ternären Operator zu verwenden.

Hinweis - Enum-Typ in einer Klasse verschachtelt (Apr 28 '11):

Wenn Ihr Enum-Typ in einer Klasse verschachtelt ist (und nicht direkt im Namespace), können Sie möglicherweise die "+"-Syntax verwenden, um auf das Enum in XAML zuzugreifen, wie in einer (nicht markierten) Antwort auf die Frage angegeben:

ConverterParameter={x:Static local: IhreKlasse+ YourNestedEnumType.Enum1}

Aus diesem Grund Microsoft Connect Problem Allerdings wird der Designer in VS2010 nicht mehr geladen und gibt an "Type 'local:YourClass+YourNestedEnumType' was not found." aber das Projekt wird kompiliert und erfolgreich ausgeführt. Natürlich können Sie dieses Problem vermeiden, wenn Sie Ihren Enum-Typ direkt in den Namespace verschieben können.


Bearbeiten (27. Januar '12):

Bei Verwendung von Enum-Flags würde der Konverter folgendermaßen aussehen:

public class EnumToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return ((Enum)value).HasFlag((Enum)parameter);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value.Equals(true) ? parameter : Binding.DoNothing;
    }
}

Bearbeiten (7. Mai '15):

Im Falle eines Nullable Enum (das **nicht** in der Frage gefragt ist, aber in einigen Fällen benötigt werden kann, z.B. ORM, das null von DB zurückgibt, oder wann immer es Sinn macht, dass in der Programmlogik der Wert nicht bereitgestellt wird), denken Sie daran, eine anfängliche null-Prüfung in der Convert-Methode hinzuzufügen und den entsprechenden bool-Wert zurückzugeben, der typischerweise false ist (wenn Sie keine Optionsschaltfläche ausgewählt haben wollen), wie unten:

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null) {
            return false; // or return parameter.Equals(YourEnumType.SomeDefaultValue);
        }
        return value.Equals(parameter);
    }

Hinweis - NullReferenceException (10. Oktober '18):

Das Beispiel wurde aktualisiert, um die Möglichkeit zu beseitigen, dass eine NullReferenceException ausgelöst wird. IsChecked" ist ein nullbarer Typ, so dass die Rückgabe von "Nullable" eine vernünftige Lösung zu sein scheint.

417voto

Lars Punkte 5803

Sie könnten einen allgemeineren Konverter verwenden

public class EnumBooleanConverter : IValueConverter
{
  #region IValueConverter Members
  public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    string parameterString = parameter as string;
    if (parameterString == null)
      return DependencyProperty.UnsetValue;

    if (Enum.IsDefined(value.GetType(), value) == false)
      return DependencyProperty.UnsetValue;

    object parameterValue = Enum.Parse(value.GetType(), parameterString);

    return parameterValue.Equals(value);
  }

  public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    string parameterString = parameter as string;
    if (parameterString == null)
        return DependencyProperty.UnsetValue;

    return Enum.Parse(targetType, parameterString);
  }
  #endregion
}

Und in dem XAML-Teil, den Sie verwenden:

<Grid>
    <Grid.Resources>
      <l:EnumBooleanConverter x:Key="enumBooleanConverter" />
    </Grid.Resources>
    <StackPanel >
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=FirstSelection}">first selection</RadioButton>
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=TheOtherSelection}">the other selection</RadioButton>
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=YetAnotherOne}">yet another one</RadioButton>
    </StackPanel>
</Grid>

27voto

anon Punkte 271

Für die Antwort EnumToBooleanConverter: Anstatt DependencyProperty.UnsetValue zurückzugeben, sollten Sie Binding.DoNothing für den Fall zurückgeben, dass der Wert der Optionsschaltfläche IsChecked falsch wird. Ersteres deutet auf ein Problem hin (und könnte dem Benutzer ein rotes Rechteck oder ähnliche Überprüfungsindikatoren anzeigen), während letzteres lediglich anzeigt, dass nichts getan werden sollte, was in diesem Fall auch gewünscht ist.

http://msdn.microsoft.com/en-us/library/system.Windows.data.ivalueconverter.convertback.aspx http://msdn.microsoft.com/en-us/library/system.Windows.data.binding.donothing.aspx

5voto

Martin Moser Punkte 550

Ich würde die RadioButtons in einer ListBox verwenden, und dann an den SelectedValue binden.

Dies ist ein älterer Thread zu diesem Thema, aber die Grundidee dürfte dieselbe sein: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/323d067a-efef-4c9f-8d99-fecf45522395/

3voto

Bei UWP ist das nicht so einfach: Sie müssen einen zusätzlichen Schritt machen, um einen Feldwert als Parameter zu übergeben.

Beispiel 1

Gilt sowohl für WPF als auch für UWP.

<MyControl>
    <MyControl.MyProperty>
        <Binding Converter="{StaticResource EnumToBooleanConverter}" Path="AnotherProperty">
            <Binding.ConverterParameter>
                <MyLibrary:MyEnum>Field</MyLibrary:MyEnum>
            </Binding.ConverterParameter>
        </MyControl>
    </MyControl.MyProperty>
</MyControl>

Beispiel 2

Gilt sowohl für WPF als auch für UWP.

...
<MyLibrary:MyEnum x:Key="MyEnumField">Field</MyLibrary:MyEnum>
...

<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={StaticResource MyEnumField}}"/>

Beispiel 3

Gilt nur für WPF!

<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static MyLibrary:MyEnum.Field}}"/>

UWP unterstützt nicht x:Static also Beispiel 3 kommt nicht in Frage; angenommen, Sie entscheiden sich für Beispiel 1 ist das Ergebnis ein ausführlicherer Code. Beispiel 2 ist etwas besser, aber immer noch nicht ideal.

Solución

public abstract class EnumToBooleanConverter<TEnum> : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var Parameter = parameter as string;

        if (Parameter == null)
            return DependencyProperty.UnsetValue;

        if (Enum.IsDefined(typeof(TEnum), value) == false)
            return DependencyProperty.UnsetValue;

        return Enum.Parse(typeof(TEnum), Parameter).Equals(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        var Parameter = parameter as string;
        return Parameter == null ? DependencyProperty.UnsetValue : Enum.Parse(typeof(TEnum), Parameter);
    }
}

Definieren Sie dann für jeden Typ, den Sie unterstützen möchten, einen Konverter, der den Enum-Typ verpackt.

public class MyEnumToBooleanConverter : EnumToBooleanConverter<MyEnum>
{
    //Nothing to do!
}

Der Grund dafür, dass es in einer Box untergebracht werden muss, ist, dass es scheinbar keine Möglichkeit gibt, auf den Typ in der Datei ConvertBack Methode; das Boxing kümmert sich darum. Wenn Sie sich für eines der ersten beiden Beispiele entscheiden, können Sie einfach auf den Parametertyp verweisen und müssen nicht von einer Box-Klasse erben; wenn Sie alles in einer Zeile und mit möglichst wenig Aufwand erledigen möchten, ist die letztere Lösung ideal.

Die Verwendung ähnelt Beispiel 2 , ist aber in der Tat weniger ausführlich.

<MyControl MyProperty="{Binding AnotherProperty, Converter={StaticResource MyEnumToBooleanConverter}, ConverterParameter=Field}"/>

Der Nachteil ist, dass Sie für jeden Typ, den Sie unterstützen möchten, einen Konverter definieren müssen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X