Jak powiązać RadioButtons z wyliczeniem?


406

Mam wyliczenie takie jak to:

public enum MyLovelyEnum
{
    FirstSelection,
    TheOtherSelection,
    YetAnotherOne
};

Mam właściwość w moim DataContext:

public MyLovelyEnum VeryLovelyEnum { get; set; }

I mam trzy RadioButtons w moim kliencie WPF.

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

Jak teraz powiązać RadioButtons z właściwością, aby uzyskać prawidłowe dwukierunkowe wiązanie?


3
Jeśli szukasz to zrobić bez określania indywidualnych radiobuttons w swojej XAML, polecam ListBox powiązany z wartościami enum jak to lub to i to ma szablonu elementu nadpisane w użyciu RadioButton jak ten .
Rachel

Odpowiedzi:


389

Możesz użyć bardziej ogólnego konwertera

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
}

A w części XAML używasz:

<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>

51
Dla mnie zadziałało jak urok. Jako dodatek zmodyfikowałem ConvertBack, aby zwracał także UnsetValue na „false”, ponieważ silverlight (i przypuszczalnie poprawny WPF) wywołuje konwerter dwa razy - raz przy wyłączaniu starej wartości przycisku opcji i ponownie, aby ustawić nową. Wieszałem inne rzeczy na ustawieniach nieruchomości, więc chciałem, żeby to się nazywało tylko raz. - if (parametrString == null || value.Equals (false)) zwraca DependencyProperty.UnsetValue;
MarcE

8
Z tego, co mogę powiedzieć, należy to zrobić, chyba że przyciski opcji znajdują się w różnych grupach (a przyciski AFAIK bez zestawu GroupName, które mają tego samego rodzica, są domyślnie w tej samej grupie). W przeciwnym razie wywołania mające na celu ustawienie właściwości „odbijanie” i nieparzyste zachowanie.
nlawalker

2
tak, ale jeśli wywołasz Unset w konwerterze przy ustawieniu na false, to nie jest to prawdziwy EnumToBooleanConverter, ale bardziej EnumToRadioButtonConverter. Zamiast tego sprawdzam, czy wartość jest inna w moim ustawiaczu właściwości: if (_myEnumBackingField == wartość) return;
Stéphane

8
Wiązanie tego rozwiązania działa poprawnie tylko w jedną stronę. Nie mogłem programowo przełączać przycisku radiowego, przypisując powiązaną właściwość do innej wartości. Jeśli chcesz poprawnego działania ORAZ lepszego rozwiązania, zastosuj podejście Scotta.
l46kok

2
@Marc, czy nie należy zwracać w tym przypadku „Binding.DoNothing”, a nie „DependencyProperty.UnsetValue”?
Mark A. Donohoe

559

Możesz dodatkowo uprościć przyjętą odpowiedź. Zamiast wpisywać wyliczenia jako ciągi znaków w xaml i wykonywać więcej pracy w konwerterze, niż to konieczne, możesz jawnie przekazać wartość wyliczenia zamiast reprezentacji ciągu, a jak skomentował CrimsonX, błędy są generowane w czasie kompilacji, a nie w czasie wykonywania:

ConverterParameter = {x: Statyczny lokalny: 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>

Następnie uprość konwerter:

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;
    }
}

Edycja (16 grudnia 10):

Dzięki anon za sugerowanie zwrotu Binding.DoNothing zamiast DependencyProperty.UnsetValue.


Uwaga - Wiele grup przycisków RadioButtons w tym samym kontenerze (17 lutego 11):

W Xaml, jeśli przyciski opcji współużytkują ten sam kontener nadrzędny, wówczas wybranie jednego spowoduje odznaczenie wszystkich pozostałych w tym kontenerze (nawet jeśli są powiązane z inną właściwością). Staraj się więc trzymać RadioButton, które są powiązane ze wspólną właściwością, zgrupowane w osobnym pojemniku, takim jak panel stosu. W przypadkach, gdy powiązane RadioButton nie mogą współużytkować jednego kontenera nadrzędnego, ustaw właściwość GroupName każdego RadioButton na wspólną wartość, aby logicznie pogrupować je.


Edytuj (5 kwietnia 11):

Uproszczone narzędzie ConvertBack, jeśli jeszcze, aby użyć operatora trójskładnikowego.


Uwaga - typ enum zagnieżdżony w klasie (28 kwietnia '11):

Jeśli Twój typ wyliczenia jest zagnieżdżony w klasie (zamiast bezpośrednio w przestrzeni nazw), możesz użyć składni „+”, aby uzyskać dostęp do wyliczenia w XAML, jak podano w (nieoznaczonej) odpowiedzi na pytanie Nie można znaleźć typ wyliczenia dla odniesienia statycznego w WPF :

ConverterParameter = {x: Statyczny lokalny: YourClass + YourNestedEnumType.Enum1}

Z powodu tego problemu z Microsoft Connect projektant w VS2010 nie będzie już ładował deklaracji "Type 'local:YourClass+YourNestedEnumType' was not found.", ale projekt się kompiluje i uruchamia pomyślnie. Oczywiście możesz uniknąć tego problemu, jeśli możesz przenieść typ wyliczenia bezpośrednio do przestrzeni nazw.


Edytuj (27 stycznia 12):

Jeśli używasz flag Enum, konwerter wyglądałby następująco:

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;
    }
}

Edycja (7 maja 15):

W przypadku Nullable Enum (które nie jest zadawane w pytaniu, ale może być potrzebne w niektórych przypadkach, np. ORM zwraca wartość null z DB lub ilekroć może mieć sens, że w logice programu wartość nie jest podana), pamiętaj, aby dodać początkowe sprawdzenie wartości zerowej w metodzie konwersji i zwrócenie odpowiedniej wartości bool, zwykle jest to fałsz (jeśli nie chcesz, aby wybrany został żaden przycisk opcji), jak poniżej:

    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);
    }

Uwaga - wyjątek NullReferenceException (10 października 18):

Zaktualizowano przykład, aby usunąć możliwość zgłaszania wyjątku NullReferenceException. IsCheckedjest typem zerowalnym, więc powrót Nullable<Boolean>wydaje się rozsądnym rozwiązaniem.


26
Zgadzam się, uważam, że to lepsze rozwiązanie. Ponadto użycie tej konwersji spowoduje uszkodzenie projektu w czasie kompilacji, a nie w czasie wykonywania, jeśli wartości wyliczenia zostaną zmienione, co jest dużą zaletą.
CrimsonX,

4
Jest to z pewnością znacznie lepsze rozwiązanie niż przyjęte. +1
OrPaz,

7
Niezłe rozwiązanie. Dodałbym, że tak naprawdę jest to tylko konwerter porównawczy porównujący 2 wartości. Może mieć bardziej ogólną nazwę niż EnumToBooleanConverter, taki jak
CompareConverter

5
@ Scott, bardzo miło. Ten konwerter jest dobry we wszystkich przypadkach, z atrybutem Flagi lub bez niego. Ale głupio byłoby w większości przypadków używać tego filtra bezpośrednio jako konwertera z enum jako flagami. Powodem jest to, że powinieneś osiągnąć wynik logiczny (| = lub ^ =) z poprzednią wartością, aby uzyskać właściwy wynik, ale konwerter nie ma dostępu do poprzedniej wartości. Następnie należy dodać wartość bool dla każdej wartości wyliczenia i wykonać właściwe obliczenia boolowskie w modelu MVVM. Ale dzięki za każdą informację, bardzo przydatna.
Eric Ouellet,

2
W Windows Phone 8 (prawdopodobnie w przypadku aplikacji Win Store) nie mamy x: static, więc nie możemy bezpośrednio użyć rozwiązania tutaj. Jednak IDE / Complier jest wystarczająco sprytny i wyszukuje ciąg znaków względem wszystkich literałów ciągów (tak mi się wydaje). np. działa <RadioButton IsChecked = "{Binding TrackingMode, ConverterParameter = Driving, Converter = {StaticResource EnumToBooleanConverter}, Mode = TwoWay}" /> Wszelkie literówki podczas jazdy byłyby wychwytywane w czasie projektowania / kompilacji, a nie w czasie wykonywania.
Adarsha,

26

W przypadku odpowiedzi EnumToBooleanConverter: Zamiast zwracać DependencyProperty.UnsetValue, rozważ zwrócenie Binding.DoNothing w przypadku, gdy wartość przycisku IsChecked przycisku opcji staje się false. Pierwszy wskazuje na problem (i może pokazywać użytkownikowi czerwony prostokąt lub podobne wskaźniki walidacji), a drugi wskazuje po prostu, że nie należy nic robić, co jest w tym przypadku potrzebne.

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


W Silverlight nie ma wiązania. To tylko WPF. Zamiast tego użyj wartości null.
Aleksander Wasiljew

1
Wiązanie Nic nie zniknęło również z UWP.
BlackICE

5

Chciałbym użyć RadioButtons w ListBox, a następnie połączyć się z SelectedValue.

To jest starszy wątek na ten temat, ale podstawowa idea powinna być taka sama: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/323d067a-efef-4c9f-8d99-fecf45522395/


Otrzymuję dwukierunkowe wiązanie wykonujące podobną metodę przy użyciu ListBox i DataTemplate, więc powinieneś.
Bryan Anderson


3
To zdecydowanie najlepsze rozwiązanie, wszystko inne powoduje nadmiarowy kod. ( Kolejny przykład użycia ListBox)
HB

3

W przypadku UWP nie jest to takie proste: musisz przeskoczyć przez dodatkowy obręcz, aby przekazać wartość pola jako parametr.

Przykład 1

Obowiązuje zarówno dla WPF, jak i UWP.

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

Przykład 2

Obowiązuje zarówno dla WPF, jak i UWP.

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

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

Przykład 3

Ważne tylko dla WPF!

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

UWP nie obsługuje, x:Staticwięc Przykład 3 nie wchodzi w rachubę; zakładając, że korzystasz z przykładu 1 , wynikiem jest bardziej szczegółowy kod. Przykład 2 jest nieco lepszy, ale wciąż nie jest idealny.

Rozwiązanie

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);
    }
}

Następnie dla każdego typu, który chcesz obsługiwać, zdefiniuj konwerter, który boksuje typ wyliczeniowy.

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

Powodem, dla którego należy umieścić w ramce jest to, że pozornie nie ma możliwości odwołania się do typu w ConvertBackmetodzie; zajmuje się tym boks. Jeśli wybierzesz jeden z dwóch pierwszych przykładów, możesz po prostu odwołać się do typu parametru, eliminując potrzebę dziedziczenia po klasie pudełkowej; jeśli chcesz zrobić to wszystko w jednym wierszu i przy możliwie najmniejszej szczegółowości, to drugie rozwiązanie jest idealne.

Użycie przypomina przykład 2 , ale w rzeczywistości jest mniej szczegółowe.

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

Minusem jest to, że musisz zdefiniować konwerter dla każdego typu, który chcesz obsługiwać.


1

Utworzyłem nową klasę do obsługi powiązania RadioButtons i CheckBoxes z wyliczeniami. Działa dla oznaczonych wyliczeń (z wieloma zaznaczeniami pól wyboru) i nieoznaczonych wyliczeń dla pól wyboru pojedynczego wyboru lub przycisków opcji. Nie wymaga też żadnych przetworników ValueConverters.

Na początku może się to wydawać bardziej skomplikowane, ale po skopiowaniu tej klasy do projektu jest to zrobione. Jest ogólny, więc można go łatwo użyć do dowolnego wyliczenia.

public class EnumSelection<T> : INotifyPropertyChanged where T : struct, IComparable, IFormattable, IConvertible
{
  private T value; // stored value of the Enum
  private bool isFlagged; // Enum uses flags?
  private bool canDeselect; // Can be deselected? (Radio buttons cannot deselect, checkboxes can)
  private T blankValue; // what is considered the "blank" value if it can be deselected?

  public EnumSelection(T value) : this(value, false, default(T)) { }
  public EnumSelection(T value, bool canDeselect) : this(value, canDeselect, default(T)) { }
  public EnumSelection(T value, T blankValue) : this(value, true, blankValue) { }
  public EnumSelection(T value, bool canDeselect, T blankValue)
  {
    if (!typeof(T).IsEnum) throw new ArgumentException($"{nameof(T)} must be an enum type"); // I really wish there was a way to constrain generic types to enums...
    isFlagged = typeof(T).IsDefined(typeof(FlagsAttribute), false);

    this.value = value;
    this.canDeselect = canDeselect;
    this.blankValue = blankValue;
  }

  public T Value
  {
    get { return value; }
    set 
    {
      if (this.value.Equals(value)) return;
      this.value = value;
      OnPropertyChanged();
      OnPropertyChanged("Item[]"); // Notify that the indexer property has changed
    }
  }

  [IndexerName("Item")]
  public bool this[T key]
  {
    get
    {
      int iKey = (int)(object)key;
      return isFlagged ? ((int)(object)value & iKey) == iKey : value.Equals(key);
    }
    set
    {
      if (isFlagged)
      {
        int iValue = (int)(object)this.value;
        int iKey = (int)(object)key;

        if (((iValue & iKey) == iKey) == value) return;

        if (value)
          Value = (T)(object)(iValue | iKey);
        else
          Value = (T)(object)(iValue & ~iKey);
      }
      else
      {
        if (this.value.Equals(key) == value) return;
        if (!value && !canDeselect) return;

        Value = value ? key : blankValue;
      }
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  private void OnPropertyChanged([CallerMemberName] string propertyName = "")
  {
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
}

Aby dowiedzieć się, jak z niego korzystać, załóżmy, że masz enum do uruchamiania zadania ręcznie lub automatycznie i można go zaplanować na dowolne dni tygodnia, a niektóre opcjonalne opcje ...

public enum StartTask
{
  Manual,
  Automatic
}

[Flags()]
public enum DayOfWeek
{
  Sunday = 1 << 0,
  Monday = 1 << 1,
  Tuesday = 1 << 2,
  Wednesday = 1 << 3,
  Thursday = 1 << 4,
  Friday = 1 << 5,
  Saturday = 1 << 6
}

public enum AdditionalOptions
{
  None = 0,
  OptionA,
  OptionB
}

Oto, jak łatwo można korzystać z tej klasy:

public class MyViewModel : ViewModelBase
{
  public MyViewModel()
  {
    StartUp = new EnumSelection<StartTask>(StartTask.Manual);
    Days = new EnumSelection<DayOfWeek>(default(DayOfWeek));
    Options = new EnumSelection<AdditionalOptions>(AdditionalOptions.None, true, AdditionalOptions.None);
  }

  public EnumSelection<StartTask> StartUp { get; private set; }
  public EnumSelection<DayOfWeek> Days { get; private set; }
  public EnumSelection<AdditionalOptions> Options { get; private set; }
}

Oto, jak łatwo jest powiązać pola wyboru i przyciski opcji z tą klasą:

<StackPanel Orientation="Vertical">
  <StackPanel Orientation="Horizontal">
    <!-- Using RadioButtons for exactly 1 selection behavior -->
    <RadioButton IsChecked="{Binding StartUp[Manual]}">Manual</RadioButton>
    <RadioButton IsChecked="{Binding StartUp[Automatic]}">Automatic</RadioButton>
  </StackPanel>
  <StackPanel Orientation="Horizontal">
    <!-- Using CheckBoxes for 0 or Many selection behavior -->
    <CheckBox IsChecked="{Binding Days[Sunday]}">Sunday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Monday]}">Monday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Tuesday]}">Tuesday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Wednesday]}">Wednesday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Thursday]}">Thursday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Friday]}">Friday</CheckBox>
    <CheckBox IsChecked="{Binding Days[Saturday]}">Saturday</CheckBox>
  </StackPanel>
  <StackPanel Orientation="Horizontal">
    <!-- Using CheckBoxes for 0 or 1 selection behavior -->
    <CheckBox IsChecked="{Binding Options[OptionA]}">Option A</CheckBox>
    <CheckBox IsChecked="{Binding Options[OptionB]}">Option B</CheckBox>
  </StackPanel>
</StackPanel>
  1. Po załadowaniu interfejsu użytkownika zostanie wybrany przycisk opcji „Ręczny” i można zmienić wybór między „Ręczny” lub „Automatyczny”, ale zawsze musi być wybrany jeden z nich.
  2. Każdy dzień tygodnia będzie odznaczony, ale dowolną liczbę z nich można zaznaczyć lub odznaczyć.
  3. „Opcja A” i „Opcja B” zostaną początkowo odznaczone. Możesz zaznaczyć jedno lub drugie, zaznaczenie jednego spowoduje odznaczenie drugiego (podobnie jak RadioButtons), ale teraz możesz także odznaczyć oba (co nie jest możliwe w przypadku RadioButton WPF, dlatego właśnie tutaj jest CheckBox)

Załóżmy, że masz 3 elementy w wyliczeniu StartTask, takie jak {Niezdefiniowany, Ręczny, Automatyczny} Chcesz ustawić domyślnie na Niezdefiniowany, ponieważ dopóki użytkownik nie ustawi wartości, jest niezdefiniowany. Ponadto: Jak traktowany jest SelectedItem? Twój ViewModel nie ma SelectedStartTask.
user1040323

W moim ViewModel właściwość StartUp jest EnumSelection<StartTask>obiektem. Jeśli spojrzysz na definicję EnumSelection<T>, zobaczysz, że ma ona właściwość Value. Dlatego model widoku nie musi mieć „SelectedStartTask”. Użyłbyś StartUp.Value. Jeśli chodzi o wartość domyślną Undefined, zobacz trzeci wyliczenie, AdditionalOptions, ma ona wartość None zamiast Undefined, ale możesz zmienić jej nazwę na dowolną.
Nick

1

Działa to również w przypadku Checkbox .

public class EnumToBoolConverter:IValueConverter
{
    private int val;
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int intParam = (int)parameter;
        val = (int)value;

        return ((intParam & val) != 0);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        val ^= (int)parameter;
        return Enum.Parse(targetType, val.ToString());
    }
}

Wiązanie pojedynczego wyliczenia z wieloma polami wyboru.


1
Mówię wam wielkie „DZIĘKI” za przysługę, jaką wyświadczyliście dla mnie. Dla mnie to zadziałało.
Elham Azadfar

0

Na podstawie EnumToBooleanConverter firmy Scott. Zauważyłem, że metoda ConvertBack nie działa na Enum z kodem flag.

Próbowałem następującego kodu:

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

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value.Equals(true))
            {
                if (((Enum)_obj).HasFlag((Enum)parameter))
                {
                    // Do nothing
                    return Binding.DoNothing;
                }
                else
                {
                    int i = (int)_obj;
                    int ii = (int)parameter;
                    int newInt = i+ii;
                    return (NavigationProjectDates)newInt;
                }
            }
            else
            {
                if (((Enum)_obj).HasFlag((Enum)parameter))
                {
                    int i = (int)_obj;
                    int ii = (int)parameter;
                    int newInt = i-ii;
                    return (NavigationProjectDates)newInt;

                }
                else
                {
                    // do nothing
                    return Binding.DoNothing;
                }
            }
        }
    }

Jedyną rzeczą, której nie mogę zabrać do pracy, jest obsada od intdo, targetTypewięc ustawiłem ją na sztywno NavigationProjectDates, do enum, którego używam. I targetType == NavigationProjectDates...


Edytuj dla bardziej ogólnego konwertera Flag Enum:

    FlagsEnumToBooleanConverter klasy publicznej: IValueConverter {
        private int _flags = 0;
        obiekt publiczny Konwertuj (wartość obiektu, typ targetType, parametr obiektu, język napisów) {
            if (wartość == null) zwraca false;
            _flags = (int) wartość;
            Wpisz t = wartość. GetType ();
            obiekt o = Enum.ToObject (t, parametr);
            return (wartość (Enum)) .HasFlag ((Enum) o);
        }

        obiekt publiczny ConvertBack (wartość obiektu, typ targetType, parametr obiektu, język napisów)
        {
            if (wartość?. Równe (prawda)? fałsz) {
                _flags = _flags | (int) parametr;
            }
            jeszcze {
                _flags = parametr _flags & ~ (int);
            }
            zwróć _flagi;
        }
    }

Ktoś zredagował moją odpowiedź, aby dodać kod z flagami, więc szczerze mówiąc, nigdy nie próbowałem / nie użyłem go sam i zastanawiałem się nad jego usunięciem, ponieważ uważam, że ma to większy sens niż sama odpowiedź. Jeśli uda mi się znaleźć trochę czasu później, mogę spróbować coś połączyć, aby przetestować ten kod, a także to, co masz, i być może pomóc w znalezieniu lepszego rozwiązania Twojego problemu.
Scott,

0

Możesz tworzyć przyciski radiowe dynamicznie, ListBoxmożesz to zrobić bez konwerterów, dość proste.

Konkretne kroki są poniżej: utwórz ListBox i ustaw pozycję ItemsSource dla pola listy jako wyliczenie MyLovelyEnumi powiąż SelectedItem obiektu ListBox z VeryLovelyEnumwłaściwością. Następnie zostaną utworzone przyciski opcji dla każdego ListBoxItem.

  • Krok 1 : dodaj wyliczenie do zasobów statycznych dla Windows, UserControl lub Grid itp.
    <Window.Resources>
        <ObjectDataProvider MethodName="GetValues"
                            ObjectType="{x:Type system:Enum}"
                            x:Key="MyLovelyEnum">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="local:MyLovelyEnum" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
  • Krok 2 : Użyj pola listy i Control Templatewypełnij każdy element jako przycisk opcji
    <ListBox ItemsSource="{Binding Source={StaticResource MyLovelyEnum}}" SelectedItem="{Binding VeryLovelyEnum, Mode=TwoWay}" >
        <ListBox.Resources>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <RadioButton
                                Content="{TemplateBinding ContentPresenter.Content}"
                                IsChecked="{Binding Path=IsSelected,
                                RelativeSource={RelativeSource TemplatedParent},
                                Mode=TwoWay}" />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.Resources>
    </ListBox>

Zaletą jest poniżej: jeśli pewnego dnia zmiany klasy enum, nie trzeba zaktualizować GUI (plik XAML).

Referencje: https://brianlagunas.com/a-better-way-to-data-bind-enums-in-wpf/

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.